日常唠叨
我艹,笑了,真给俺气笑了,我不知道我对题目难度的感知程度怎么可以如此逆天,我感知的难度是 : 没做
这个 不是我第一次见,但我第一次见的时候我是花了二十多分钟都没想出来,真的,二十多分钟,我人都蒙了,这个好像是 里面的一道 B. Good times Good times ,哦,那场我打的也很懵逼, 读错题,没做出来, 也想不出来,我心态居然没崩,然后跳过把 和 做了。
就很常规,是我印象中的牛客周赛 的难度。
然后是 题也很难绷,一开始我的思路就想岔了,我想的是去完整地找到那个环,然后把环上的每条边保存下来,到时候找非环上的边即可,我写了四版才过,我当时的确是有怀疑过牛客周赛的 就这么有难度了吗,这么考验代码能力了吗,但这个怀疑只是一瞬,毕竟只是两个 嘛,也能写,也能写。能写个屁,,当时愣是没想过换个思路,真是服了。我当时写的时候还在骂出题人,因为我用了时间戳的思想,这个也是我之前做到一道基环树学到的东西,我当时就在想,如果我之前没学过时间戳,今天不就死在这儿了,这题出的真刁钻,现在想想就好笑,对不起,是我唐突了,嘴贱
然后是 ,画了个图,猜了一下答案,就过了。我一直觉得数学几何和代数不是一个门类,他们甚至都统称数学是我一直所不能理解的,代数就是个玄学,就这个 题,算是代数吧,我应该一眼看出来 是 的 倍吗?我不知道你们是怎么想到把 整体往左移,然后在后面的 上面加上 的,我不理解,我永远都无法理解
最后是 ,一眼动态规划,没什么好说的,三个东西做好即可:状态,转移,初始化
这个 ,不是很懂,即使最后过了我也不是很懂,我能说清楚每一步在干嘛,但我说不清楚上一步是怎么自然而然推导下一步的
A-小红的倍数构造
题意
给出一个整数 ,请你找到 的倍数 ,使得 且 的数字构成与 相同
思路
将 看成是字符串,最后 的形式为 ,赠送一题:CF 2241B
代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define endl '\n'
typedef long long LL;
#define PLL pair<LL, LL>
const LL MOD = 998244353;
const LL MAX = 1e6 + 100;
const LL INF = 0x3f3f3f3f3f3f3f;
void solve() {
string s;
cin >> s;
cout << s << s << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
LL T = 1;
//cin >> T;
while (T--) {
solve();
}
return 0;
}
小红的连通块构造
题意
给出一个整数 ,构造出一个 行 列仅包含 的网格图,使得 所形成的联通块的个数为 ,如果无法构造出来,则输出
思路
对于 行 列构造出来的最多的连通块个数为 , 其构造方式为 交错,每行 个,共有 行。若 ,则输出 ,若小于等于,则按 交错的方式挨个给出一,直到给完 个一
代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define endl '\n'
typedef long long LL;
#define PLL pair<LL, LL>
const LL MOD = 998244353;
const LL MAX = 1e6 + 100;
const LL INF = 0x3f3f3f3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<vector<int>> g(10, vector<int>(10, 0));
if (n > 21)
{
cout << -1 << endl;
return;
}
int op = 2;
for (int i = 1; i <= 7; i++)
{
op = 3 - op;
for (int j = op; j <= 6; j += 2)
{
if (n == 0)
break;
g[i][j] = 1;
--n;
}
}
for (int a = 1; a <= 7; ++a)
{
for (int b = 1; b <= 6; ++b)
{
cout << g[a][b];
}
cout << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
LL T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
小红的基环树
题意
给出一个由 个点构成的树,再额外加一条边,构成一颗基环树,请输出任意一条非环上的边
思路
找到度为一的点,与他相连的另一个点(且是唯一一点)所构成的边即满足条件
正解代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define endl '\n'
typedef long long LL;
#define PLL pair<LL, LL>
const LL MOD = 998244353;
const LL MAX = 1e6 + 100;
const LL INF = 0x3f3f3f3f3f3f3f;
void solve() {
int n;
cin >> n;
vector<vector<int>> G(n + 1);
vector<int> deg(n + 1, 0);
for (int i = 1; i <= n; ++i) {
int u, v;
cin >> u >> v;
deg[u]++;
deg[v]++;
G[u].push_back(v);
G[v].push_back(u);
}
for (int i = 1; i <= n; ++i) {
if (deg[i] == 1) {
cout << i << " " << G[i][0] << endl;
return;
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
LL T = 1;
//cin >> T;
while (T--) {
solve();
}
return 0;
}
我当时过题的傻逼代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define endl '\n'
typedef long long LL;
#define PLL pair<LL, LL>
const LL MOD = 998244353;
const LL MAX = 1e6 + 100;
const LL INF = 0x3f3f3f3f3f3f3f;
void solve()
{
LL n;
cin >> n;
vector<PLL> tmp;
vector<vector<LL>> G(n + 1);
for (LL i = 1; i <= n; ++i)
{
LL u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
tmp.push_back({u, v});
}
vector<LL> dep(n + 1, 0);
PLL ans;
map<PLL, LL> mp;
auto dfs = [&](auto &&dfs, LL u, LL k, LL par) -> void
{
dep[u] = k + 1;
for (LL v : G[u])
{
if (v == par)
continue;
if (dep[v])
{
ans = {u, v};
return;
}
dfs(dfs, v, dep[u], u);
}
};
dfs(dfs, 1, 0, 0);
mp[{ans.first, ans.second}] = 1;
auto dfs1 = [&](auto &&dfs1, LL u, LL par) -> void
{
for (LL v : G[u])
{
if (dep[v] == dep[u] - 1 && dep[v] >= min(dep[ans.first], dep[ans.second]))
{
mp[{u, v}] = 1;
dfs1(dfs1, v, u);
}
}
};
if (dep[ans.first] < dep[ans.second]) {
int mn = min(dep[ans.first], dep[ans.second]);
int mx = max(dep[ans.first], dep[ans.second]);
swap(ans.first, ans.second);
dep[ans.first] = mx;
dep[ans.second] = mn;
}
// cout << ans.first << " " << ans.second << endl;
// cout << dep[ans.first] << " " << dep[ans.second] << endl;
dfs1(dfs1, ans.first, ans.second);
for (auto [u, v] : tmp)
{
if (mp.count({u, v}) || mp.count({v, u}))
{
continue;
}
cout << u << " " << v << endl;
return;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
LL T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
小红的计算几何
题意
给出一个边长为 的正方形,左上角坐标为 ,将其沿一条直线移动到,左上角坐标重合,算出该正方形移动过程中扫过的面积
思路
几何题,最重要的就是画图,一张图胜过千言万语

代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define endl '\n'
typedef long long LL;
#define PLL pair<LL, LL>
const LL MOD = 998244353;
const LL MAX = 1e6 + 100;
const LL INF = 0x3f3f3f3f3f3f3f;
void solve() {
LL k, a, b, c, d;
cin >> k >> a >> b >> c >> d;
LL ans = 0;
ans += abs(b - d) * k;
ans += abs(a - c) * k;
ans += k * k;
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
LL T = 1;
//cin >> T;
while (T--) {
solve();
}
return 0;
}
小红的不相邻取数
题意
给出两个数组 ,他们共同构成数组 ,构成规则是:第 段元素由 个 构成。问,在数组 中取任意个互不相邻的元素(可以不取),其和最大为多少
思路
三部曲:
- 设置状态
: 轮到第 组数, 代表该组数最后一个不取,反之,则取
- 状态转移, 分类讨论
若第 组个数为奇数:
若第 组个数为偶数:
哦对,还有一点,我管你奇数偶数,这一次都要先”延续”上一次的状态, 这个代表的是第 组一个都不取:
- 初始化
由于 可能为负数,所以非法状态不能设置为 ,而应该是负无穷 ,并且设置 ,其含义是一个都不选的话,答案为
代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define endl '\n'
typedef long long LL;
#define PLL pair<LL, LL>
const LL MOD = 998244353;
const LL MAX = 1e6 + 100;
const LL INF = 0x3f3f3f3f3f3f3f;
void solve() {
LL n;
cin >> n;
vector<LL> a(n+ 1), b(n+ 1);
for(LL i = 1; i <= n; ++i) {
cin >> a[i];
}
for (LL i = 1;i <= n; ++i) {
cin >> b[i];
}
vector<vector<LL>> dp(n + 1,vector<LL>(3, -INF));
dp[0][0] = 0;
for (LL i = 1;i <= n; ++i) {
dp[i][0] = max(dp[i][0], dp[i - 1][1]);
dp[i][0] = max(dp[i][0], dp[i - 1][0]);
if (b[i] & 1) {
dp[i][1] = max(dp[i][1], dp[i - 1][1] + b[i] / 2 * a[i]);
dp[i][1] = max(dp[i][1], dp[i - 1][0] + (b[i] + 1) / 2 * a[i]);
dp[i][0] = max(dp[i][0], dp[i - 1][0] + b[i] / 2 * a[i]);
dp[i][0] = max(dp[i][0], dp[i - 1][1] + b[i] / 2 * a[i]);
}
else {
dp[i][1] = max(dp[i][1], dp[i - 1][1] + b[i] / 2 * a[i]);
dp[i][1] = max(dp[i][1], dp[i - 1][0] + b[i] / 2 * a[i]);
dp[i][0] = max(dp[i][0], dp[i - 1][0] + b[i] / 2 * a[i]);
if (b[i] >= 2) {
dp[i][0] = max(dp[i][0], dp[i - 1][1] + (b[i] / 2 - 1) * a[i]);
}
}
}
cout << max({dp[n][0], dp[n][1], 0LL}) << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
LL T = 1;
//cin >> T;
while (T--) {
solve();
}
return 0;
}
猴子排序的剪枝
题意
给出一个大小为 的数组 ,每次可以在数组 剩余的数中等概率地选择一个数插入到新数组的末尾,若出现了逆序对,则删除新数组,重新开始操作;若构成了大小为 的非递减序列,则该轮成功,结束操作。问从第一次开始到整个过程结束,插入操作次数的期望
思路
虽然我理解的不透彻,但我尽量讲清楚我理解的所有
妈的,把老子的高中数学底子都给逼出来了,来吧来吧,公式推导:
, 即每一轮的概率乘以相应的轮数
求 :
举个例子,n = 11, 1 1 4 4 4 2 2 4 4 5 1,要想该轮成功结束,最后的形式一定是 1 1 1 2 2 4 4 4 4 4 5, 单调非递减序列,而形成这个序列的概率是多少呢?选出第一个 的概率是 ,选出第二个 的概率是 ,选出第三个 的概率是 ,选出第一个 的概率是 …… 最后选出最后一个 的概率是 ,其等于 。而每一组其内部可以任意交换,比如第一组 可能是 ,也可能是 ,也可能是 ,该组内部交换的方案数为 。设 为第 组的大小,共有 组,则总的方案数为
得
求 :
该怎么求一个插入次数至少为 的概率呢?
: 长度为 的非递减子序列的方案数
:长度为 的子序列方案数
得
公式化简:
求 :
: 轮到第 组数时,共选取长度为 的非递减子序列的方案数
: 第 组的大小
太不容易了,太他妈不容易了,总算写完了₍^ >ヮ<^₎ .ᐟ.ᐟ
视频
以下是我录的视频,我以为我不会写题解的,谁知道一开始推公式,之后就停不下来了,就给写完了,但视频不能白录吧,但是视频里面有至少三处错误,建议别看,因为我当时其实没想太清楚,录个视频更多的也是帮我理思路。但如果你跟我一样有阅读困难,那也是可以看一看的
代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & (-x))
#define endl '\n'
typedef long long LL;
#define PLL pair<LL, LL>
const LL MOD = 998244353;
const LL MAX = 1e6 + 100;
const LL INF = 0x3f3f3f3f3f3f3f;
void solve() {
int n;
cin >> n;
comb.init(n);
map<int, int> mp;
for (int i = 1;i <= n; ++i) {
int x;
cin >> x;
mp[x]++;
}
Z coef = 1, ans =0 ;
int tot = 0;
int m = mp.size();
vector<int> a(m + 1, 0);
for (auto [c, cnt] : mp)
{
coef *= comb.fac(cnt);
a[++tot] = cnt;
}
vector<vector<Z>> dp(m + 1, vector<Z>(n + 1, 0));
dp[0][0] = 1;
for (int i = 1; i <= m; ++i) {
for (int j = 0; j <= n; ++j) {
for (int k = 0; k <= min(a[i], j); ++k)
{
dp[i][j] += dp[i - 1][j - k] * comb.A(a[i], k);
}
}
}
vector<Z> s(n + 1);
for (int i = 0; i < n; ++i) {
s[i] = dp[m][i];
}
for (int i = 0; i < n; ++i) {
ans += s[i] * comb.fac(n - i);
}
ans /= coef;
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
LL T = 1;
//cin >> T;
while (T--) {
solve();
}
return 0;
}
组合数+取模类
using i64 = long long;
template<class T>
constexpr T power(T a, i64 b)
{
T res = 1;
for (; b; b >>= 1, a *= a)
{
if (b & 1)
{
res *= a;
}
}
return res;
}
template<int P>
struct MInt
{
int x;
constexpr MInt() : x(0) {}
constexpr MInt(i64 v)
{
x = v % P;
if (x < 0)
{
x += P;
}
}
constexpr int val() const
{
return x;
}
constexpr MInt inv() const
{
return power(*this, P - 2);
}
constexpr MInt& operator+=(const MInt& rhs)
{
x += rhs.x;
if (x >= P)
{
x -= P;
}
return *this;
}
constexpr MInt& operator-=(const MInt& rhs)
{
x -= rhs.x;
if (x < 0)
{
x += P;
}
return *this;
}
constexpr MInt& operator*=(const MInt& rhs)
{
x = 1LL * x * rhs.x % P;
return *this;
}
constexpr MInt& operator/=(const MInt& rhs)
{
return *this *= rhs.inv();
}
friend constexpr MInt operator+(MInt a, const MInt& b)
{
return a += b;
}
friend constexpr MInt operator-(MInt a, const MInt& b)
{
return a -= b;
}
friend constexpr MInt operator*(MInt a, const MInt& b)
{
return a *= b;
}
friend constexpr MInt operator/(MInt a, const MInt& b)
{
return a /= b;
}
friend ostream& operator<<(ostream& os, const MInt& a)
{
return os << a.x;
}
friend istream& operator>>(istream& is, MInt& a)
{
i64 v;
is >> v;
a = MInt(v);
return is;
}
};
using Z = MInt<998244353>;
struct Comb
{
int n;
vector<Z> fac_;
vector<Z> ifac_;
vector<Z> inv_;
Comb() : n(0), fac_(1, 1), ifac_(1, 1), inv_(1, 0) {}
void init(int m)
{
if (m <= n)
{
return;
}
fac_.resize(m + 1);
ifac_.resize(m + 1);
inv_.resize(m + 1);
for (int i = n + 1; i <= m; i++)
{
fac_[i] = fac_[i - 1] * i;
}
ifac_[m] = fac_[m].inv();
for (int i = m; i > n; i--)
{
ifac_[i - 1] = ifac_[i] * i;
inv_[i] = ifac_[i] * fac_[i - 1];
}
n = m;
}
Z fac(int m)
{
if (m > n)
{
init(2 * m);
}
return fac_[m];
}
Z ifac(int m)
{
if (m > n)
{
init(2 * m);
}
return ifac_[m];
}
Z inv(int m)
{
if (m > n)
{
init(2 * m);
}
return inv_[m];
}
Z C(int n, int m)
{
if (m < 0 || m > n)
{
return 0;
}
return fac(n) * ifac(m) * ifac(n - m);
}
Z A(int n, int m)
{
if (m < 0 || m > n)
{
return 0;
}
return fac(n) * ifac(n - m);
}
};
Comb comb;