2023牛客暑期多校训练营3 ABDHJ
A
题解
知识点:数学。
当 时,当且仅当 可行。
当 时,一定可行,答案为 。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); string x, y; cin >> x >> y; ll X = 0, Y = 0; for (int i = 0;i < x.size();i++) (X <<= 1) |= x[i] - '0'; for (int i = 0;i < y.size();i++) (Y <<= 1) |= y[i] - '0'; if (X == 0) { if (Y == 0) cout << 0 << '\n'; else cout << -1 << '\n'; } else cout << abs(X - Y) << '\n'; return 0; }
B
题解
知识点:排列组合,计数dp。
注意到,最后的排列一定是一段小数 ,一段大数 交替。
考虑设 表示填了 个小数, 个大数,最后一段是小数或大数段的合法方案数(注意这里没包括最后一个错误的牌),有转移方程:
if (k <= i) f[i][j][0] += f[i - k][j][1] * CNM::C(n - i + k, k); if (k <= j) f[i][j][1] += f[i][j - k][0] * CNM::C(n - j + k, k);
其中 为最后一段数字的个数。
统计答案时,我们考虑每个位置猜对时产生的贡献。对于前 个小数, 个大数猜对时的方案数量为:
此时的所有方案,一定会在第 的位置产生一张猜对的牌的贡献。
最后我们需要加上每个排列最后一张错误的牌,共 种方案会产生一张错误的牌。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; struct Modint { static int P; int val; Modint(int _val = 0) :val(_val %P) { format(); } Modint(ll _val) :val(_val %P) { format(); } //if val in [-P,2P) Modint &format() { if (val < 0) val += P; if (val >= P) val -= P; return *this; } Modint inv()const { return qpow(*this, P - 2); } Modint &operator+=(const Modint &x) { val += x.val;return format(); } Modint &operator-=(const Modint &x) { val -= x.val;return format(); } Modint &operator*=(const Modint &x) { val = 1LL * val * x.val % P;return *this; } Modint &operator/=(const Modint &x) { return *this *= x.inv(); } friend Modint operator-(const Modint &x) { return { -x.val }; } friend Modint operator+(Modint a, const Modint &b) { return a += b; } friend Modint operator-(Modint a, const Modint &b) { return a -= b; } friend Modint operator*(Modint a, const Modint &b) { return a *= b; } friend Modint operator/(Modint a, const Modint &b) { return a /= b; } friend Modint qpow(Modint a, ll k) { Modint ans = 1; while (k) { if (k & 1) ans = ans * a; k >>= 1; a = a * a; } return ans; } friend istream &operator>>(istream &is, Modint &x) { ll _x; is >> _x; x = { _x }; return is; } friend ostream &operator<<(ostream &os, const Modint &x) { return os << x.val; } }; /// 自动取模整数,O(logk)快速幂、O(logP)逆元、O(1)运算 int P; namespace CNM { const int N = 3e2 + 7; int c[N][N]; void init(int n) { for (int i = 0;i <= n;i++) for (int j = 0;j <= i;j++) c[i][j] = 0 < j && j < i ? (c[i - 1][j - 1] + c[i - 1][j]) % P : 1; } int C(int n, int m) { if (n == m && m == -1) return 1; //* 隔板法特判 if (n < m || m < 0) return 0; return c[n][m]; } } int Modint::P = 1e9 + 7; Modint f[307][307][2]; Modint fact[607]; bool solve() { int n; cin >> n >> P; Modint::P = P; CNM::init(n); fact[0] = 1; for (int i = 1;i <= 2 * n;i++) fact[i] = fact[i - 1] * i; for (int i = 0;i <= n;i++) for (int j = 0;j <= n;j++) f[i][j][0] = f[i][j][1] = 0; f[0][0][0] = f[0][0][1] = 1; Modint ans = 0; for (int i = 0;i <= n;i++) { for (int j = 0;j <= n;j++) { for (int k = 1;k <= n;k++) { if (k <= i) f[i][j][0] += f[i - k][j][1] * CNM::C(n - i + k, k); if (k <= j) f[i][j][1] += f[i][j - k][0] * CNM::C(n - j + k, k); } if (i + j > 0) ans += (f[i][j][0] + f[i][j][1]) * fact[2 * n - i - j];// 第i+j张牌正确时的贡献 = 至少在i+j前正确时的方案数 * 1 } } ans += fact[2 * n]; // 所有排列都会有一张错误的牌 ans -= f[n][n][0] + f[n][n][1]; // 除了全对的排列 cout << ans << '\n'; return true; } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t = 1; cin >> t; while (t--) { if (!solve()) cout << -1 << '\n'; } return 0; }
D
题解
知识点:位运算,数学。
注意到,最终只有全 或 的情况才是合法的。因此考虑从这两种情况逆推,不妨考虑全 情况。
我们发现,无论如何操作,所有行都和第一行或者第一行取反一致(对列一样,这里只需要考虑行即可)。因此,一开始先判断矩阵是否合法,再进行操作次数的计算。
对于操作次数, 最小值为第一行的 最少数量加第一列的 最少数量。因为,我们先对行操作把一行对齐,此时所有行都是一样的,在对列操作即可。对行操作的次数,即第一列的 最少数量;之后,对列操作的次数,即第一行的 最少数量。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; int a[2007][2007]; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 1;i <= n;i++) for (int j = 1;j <= n;j++) { char ch; cin >> ch; a[i][j] = ch == '1'; } for (int i = 1;i <= n;i++) { bool ok = 1, f = a[i][1] == a[1][1]; for (int j = 1;j <= n;j++) ok &= (a[i][j] == a[1][j]) == f; if (!ok) { cout << -1 << '\n'; return 0; } } array<int, 4> cnt{}; for (int i = 1;i <= n;i++) { if (a[1][i]) cnt[1]++; else cnt[0]++; if (a[i][1]) cnt[2 + 1]++; else cnt[2 + 0]++; } cout << min(cnt[0], cnt[1]) + min(cnt[2], cnt[3]) << '\n'; return 0; }
H
题解
知识点:数论。
显然,操作可以使得数字任意分配,但总和不变,因此考虑总和能否构造为质数序列。
哥德巴赫猜想:对于一个大于等于 的偶数,总能分为两个质数之和。(人类探索范围没有反例)
分类讨论:
-
当 时,判断是否为质数即可。
-
当 时,若 则无解。
否则,若 是奇数,那么 是质数即可;若 是偶数,根据哥德巴赫猜想一定有解。
-
当 时,若 则无解。
否则,若 是奇数,前面放 个 和 个 ,最后还剩大于等于 的偶数,根据哥德巴赫猜想一定有解 ;若 是偶数,根据哥德巴赫猜想一定有解。
综上 一定有解。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; bool isPrime(int n) { if (n == 2) return 1; if (n == 1) return 0; for (int i = 2;i * i <= n;i++) if (!(n % i)) return 0; return 1; } /// 试除法,O(n^(1/2)),枚举[1,sqrt(n)]作为质因子判断素数 int a[1007]; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; ll sum = 0; for (int i = 1;i <= n;i++) cin >> a[i], sum += a[i]; if (n == 1) { if (isPrime(a[1])) cout << "Yes" << '\n'; else cout << "No" << '\n'; return 0; } if (n == 2) { if (sum >= 2 * n) { if (sum & 1) { if (isPrime(sum - 2)) cout << "Yes" << '\n'; else cout << "No" << '\n'; } else cout << "Yes" << '\n'; } else cout << "No" << '\n'; return 0; } if (sum >= 2 * n) { if (sum & 1) { if (isPrime(sum - (n - 1) * 2)) cout << "Yes" << '\n'; else if (sum - (n - 3) * 2 - 3 >= 4) cout << "Yes" << '\n'; else cout << "No" << '\n'; } else cout << "Yes" << '\n'; } else cout << "No" << '\n'; return 0; }
J
题解
知识点:拓扑排序。
显然,若原图是dag,拓扑序就是最终结果。
否则,一定需要两个排名序列,直接输出 到 正序反序即可。
实现用一次拓扑排序即可完成判环和拓扑序。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 1e6 + 7; int n, m; vector<int> g[N]; int deg[N]; int ans[N], cnt; queue<int> q; void toposort() { cnt = 0; for (int i = 1;i <= n;i++) deg[i] = 0; for (int i = 1;i <= n;i++) for (auto v : g[i]) deg[v]++; for (int i = 1;i <= n;i++) if (!deg[i]) q.push(i); while (!q.empty()) { int u = q.front(); q.pop(); ans[++cnt] = u; for (auto v : g[u]) { deg[v]--; if (!deg[v]) q.push(v); } } } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> m; for (int i = 1;i <= m;i++) { int u, v; cin >> u >> v; g[u].push_back(v); } toposort(); if (cnt == n) { cout << 1 << '\n'; for (int i = 1;i <= n;i++) cout << ans[i] << " \n"[i == n]; } else { cout << 2 << '\n'; for (int i = 1;i <= n;i++) cout << i << " \n"[i == n]; for (int i = 1;i <= n;i++) cout << n + 1 - i << " \n"[i == n]; } return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17582861.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2022-07-26 蔚来杯2022牛客暑期多校训练营3 AC
2022-07-26 蔚来杯2022牛客暑期多校训练营2 GJK
2022-07-26 蔚来杯2022牛客暑期多校训练营1 ACDGI