Educational Codeforces Round 136 (Rated for Div. 2) A-E
A
题解
知识点:模拟。
所有点都跑一遍即可。
另外可以不模拟, 的情况都可以摆在 这个点,其他摆在 。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; const int dir[8][2] = { {-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1} }; bool solve() { int n, m; cin >> n >> m; int x = n, y = m; for (int i = 1;i <= n;i++) { for (int j = 1;j <= m;j++) { bool ok = false; for (int k = 0;k < 8;k++) { int xx = i + dir[k][0]; int yy = j + dir[k][1]; ok |= xx >= 1 && xx <= n && yy >= 1 && yy <= m; } if (!ok) { x = i; y = j; break; } } } cout << x << ' ' << y << '\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; }
B
题解
知识点:贪心。
显然,根据 可以得到 ,但 ,因此如果 且 时说明有两个合法 输出 ,否则继续构造。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; int d[107]; bool solve() { int n; cin >> n; for (int i = 1;i <= n;i++) cin >> d[i]; for (int i = 2;i <= n;i++) { if (d[i] && d[i - 1] - d[i] >= 0) return false; d[i] += d[i - 1]; } for (int i = 1;i <= n;i++) cout << d[i] << ' '; cout << '\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; }
C
题解
知识点:排列组合,构造,线性dp。
总局面一共 种。
注意到平局只有 种情况,即每次最大的牌都在对方手里,而自己手里有次大的牌,如此就能构造出平局的局面了。比如在 时,平局为 拥有 , 有 。因此只要求出 赢局面,就能得到 赢局面。
如果 的局面比其平局局面的从大到小的某一回合牌更大(前面回合的牌和平局一样,后面的牌随意分配),那么 赢。如 有 , 一样但 比 大,因此 赢。对 也是同理的。
再者,我们注意到,局面情况是可以递推的。如 时第一回合结束就来到 的情况,不过 成先手了。
因此我们对 的局面,可以先求出第一回合的情况,再用 的结果即可。
显然第一回合 赢的情况,只有牌是最大 的时候,此时剩下的牌可以随便选,一共有 种,接下来的情况和 时 赢等价。
我们定义 为 时 赢的局面数, 为 时 赢的局面数。 有递推关系:
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; const int mod = 998244353; int ansA[67], ansB[67]; int C[67][67]; void init(int n = 60) { for (int i = 0;i <= n;i++) { for (int j = 0;j <= i;j++) { if (j == 0 || i == j) C[i][j] = 1; else C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod; } } } void get(int n = 60) { ansA[2] = 1; ansB[2] = 0; for (int i = 4;i <= n;i += 2) { ansA[i] = (C[i - 1][i / 2 - 1] + ansB[i - 2]) % mod; ansB[i] = (C[i][i / 2] - ansA[i] - 1 + mod) % mod; } } bool solve() { int n; cin >> n; cout << ansA[n] << ' ' << ansB[n] << ' ' << 1 << '\n'; return true; } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t = 1; cin >> t; init(); get(); while (t--) { if (!solve()) cout << -1 << '\n'; } return 0; }
D
题解
知识点:二分,树形dp。
这道题答案具有单调性,因此可以二分答案 。
设 为节点 希望的高度。自底向上处理,把叶子节点希望高度设为 。父节点的希望高度为所有子节点希望高度最小值减 。
当 时,除了节点 和父节点是 的节点,都属于需要操作的节点,因此操作次数加 。但要注意,操作过的节点希望高度需要设为 ,这个子节点已经与原来的父节点分离了,其希望高度不能影响到原来的父节点,所以设为父节点可能的希望高度最大值加 。
最后判断一下操作次数有没有超过 来进行二分即可。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; vector<int> g[200007]; int dp[200007]; int n, k; int mid, cnt; void dfs(int u, int fa) { dp[u] = mid; for (auto v : g[u]) { if (v == fa) continue; dfs(v, u); dp[u] = min(dp[u], dp[v] - 1); } if (dp[u] == 1 && fa != 1 && u != 1) { cnt++; dp[u] = mid + 1; } } bool check(int mid) { cnt = 0; dfs(1, 0); return cnt <= k; } bool solve() { cin >> n >> k; for (int i = 1;i <= n;i++) g[i].clear(); for (int i = 2;i <= n;i++) { int u; cin >> u; g[i].push_back(u); g[u].push_back(i); } int l = 1, r = n - 1; while (l <= r) { mid = l + r >> 1; if (check(mid)) r = mid - 1; else l = mid + 1; } cout << l << '\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; }
E
题解
知识点:状压dp。
设 表示清理到第 列第 行格子且第 列及以前的格子也都清理时,机器人清理的最大格子数。
假设机器人走到了第 列第 行(接下来称为 ),接下来有两种走法:继续往右直走,换另一行往右直走。
-
第一种情况往右直走,此时我们需要手动保证 没垃圾,但其影响不了机器人下一步行动,所以可以直接转移:
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j] + (s[j][i + 1] == '1')); -
第二种情况换行往右直走,但这种情况建立在 有垃圾,否则机器人不会换行。此时我们需要手动保证 没垃圾,但不能直接转移到 ,因为此时转移的状态是建立在 一定没有垃圾的情况。但 也有可能会从 转移过来,这个转移是没有限制的。因此转移的前提都不同了,所以第二种转移具有后效性。解决方案是继续顺着走到 ,既然 在这种情况下保证没有垃圾了,不妨继续走到 ,此时是没有后效性的,转移方程为:
dp[min(i + 2, n)][j ^ 1] = max(dp[min(i + 2, n)][j ^ 1], dp[i][j] + 1 + (s[j ^ 1][i + 1] == '1') + (s[j ^ 1][i + 2] == '1'));
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; int dp[200007][2]; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; string s[2]; cin >> s[0] >> s[1]; memset(dp, -0x3f, sizeof(dp)); dp[0][0] = 0; for (int i = 0;i < n;i++) { for (int j = 0;j < 2;j++) { dp[i + 1][j] = max(dp[i + 1][j], dp[i][j] + (s[j][i + 1] == '1')); if (s[j ^ 1][i] == '1') dp[min(i + 2, n)][j ^ 1] = max(dp[min(i + 2, n)][j ^ 1], dp[i][j] + 1 + (s[j ^ 1][i + 1] == '1') + (s[j ^ 1][i + 2] == '1')); } } cout << max(dp[n][0], dp[n][1]) << '\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16773075.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧