Codeforces Round #821 (Div. 2) A-E
A
题解
知识点:贪心。
下标模 相同分为一组,共有 组,组间不能互换,组内任意互换。
题目要求连续 个数字,一定能包括所有的 组,现在只要在每组中选取最大的加在一起即可。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; int a[107]; bool solve() { int n, k; cin >> n >> k; for (int i = 1;i <= n;i++) cin >> a[i]; ll ans = 0; for (int i = 1;i <= k;i++) { int mx = 0; for (int j = i;j <= n;j += k) mx = max(mx, a[j]); ans += mx; } 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; }
B
题解
知识点:构造。
注意到,必然会有人赢 次,有人会赢非 次,因此 或者 都是不存在的。
假设非 数为 ,即赢的人都赢 次,其他人都直接输掉,因为共有 次机会,那么只有 时合法,其余情况不存在。
在合法的情况下,尝试构造。我们只需要确定第一场赢的人,然后每隔 场换个人即可。为了方便,我们确定 为第一场赢的人,这样我们对人的编号加 就是下一个人。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; bool solve() { int n, x, y; cin >> n >> x >> y; if (x && y || !x && !y) return false; if (x < y) swap(x, y); if ((n - 1) % x) return false; else { for (int i = 2;i <= n;i += x) { for (int j = 1;j <= x;j++) cout << 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
题解
知识点:构造。
考虑通过 次操作使得序列元素全部相等。
注意到同奇同偶和为偶数使数字向左转移,否则为奇数使数字向右转移。
显然,可以通过第一个数字把右侧所有与之奇偶性不同的数字变成相等的,现在考虑与第一个数字奇偶性相同的数字相等。
因为同奇偶性,所以只能向左转移。考虑找到最后一个与第一个数字同奇偶性的数字,随后通过这个数字向左把同奇偶性的数字都变为相等,之后再执行上一步把不同奇偶性的数字变成相等的。
上述操作,每次都能增加一个与初始数字确定相等的数字,所以共操作 次。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; bool vis[100007]; bool solve() { int n; cin >> n; int ls = 1; for (int i = 1, x;i <= n;i++) { cin >> x; vis[i] = x & 1; if (vis[1] == vis[i]) ls = i; } cout << n - 1 << '\n'; for (int i = ls - 1;i >= 1;i--) { if (vis[i] == vis[1]) cout << i << ' ' << ls << '\n'; } for (int i = 2;i <= n;i++) { if (vis[1] != vis[i]) cout << 1 << ' ' << i << '\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
题解
知识点:区间dp,贪心。
任何时候,如果需要修改的地方是奇数,则不存在解法,即 情况。
简单版本,规定 ,因此:
- 当需要修改的位置 时,可以每次隔一个取,使花费永远是 ,最终花费是 。
- 当 时,除了花费 直接消掉,还可以通过一个其他不相邻的位置中转,两次不相邻修改实现一次相邻修改,花费 ,因此总花费是 。
困难版本,没有规定 关系,但 那部分可以直接用贪心结论解决, 只能dp解决了,这里采用线性dp,其他dp也能做。
设 表示从 到 修改成一样的最小花费。
当 为偶数时, :
- 修改了前 个位置的花费,加上链式 修改第 和 个的花费。
- 修改了前 个位置除了一个位置没修改(可能在任何位置,也即包括了在第 处)的花费,加上不相邻修改 的花费。
取最小值。其中前者修改不需要考虑 ,因为后者包括了;后者不需要考虑 链式修改,可以证明不可能更优。
当 为奇数时, :
- 修改了前 个位置除了一个位置没修改的花费,加上链式 修改第 和 个的花费。
- 修改了前 个位置的花费,留下第 处没修改。
取最小值。其中前者修改不需要考虑 不相邻修改,因为前者如果使用 修改 和 ,花费等价于 的情况之一,即 ,后者更优在于保留了第 个位置而非更前的位置,对偶数情况有更好的影响。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; ll dp[5007]; bool solve() { int n; ll x, y; string a, b; vector<int> v; cin >> n >> x >> y; cin >> a >> b; v.clear(); for (int i = 0;i < n;i++) { if (a[i] != b[i]) v.push_back(i); } if (v.size() & 1) return false; if (!v.size()) { cout << 0 << '\n'; return true; } if (x >= y) { if (v.size() == 2 && v.front() + 1 == v.back()) cout << min(x, 2 * y) << '\n'; else cout << v.size() / 2LL * y << '\n'; } else { dp[0] = 0; dp[1] = min((v[1] - v[0]) * x, y); for (int i = 2;i < v.size();i++) { if (i & 1) dp[i] = min(dp[i - 2] + (v[i] - v[i - 1]) * x, dp[i - 1] + y); else dp[i] = min(dp[i - 2] + (v[i] - v[i - 1]) * x, dp[i - 1]); } cout << dp[v.size() - 1] << '\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] += dp[i][j] / 2; dp[i][j + 1] += dp[i][j] - dp[i + 1][j];
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; ll get(ll t, int x, int y) { vector<vector<ll>> dp(x + 7, vector<ll>(y + 7)); dp[0][0] = max(t - (x + y) + 1, 0LL); for (int i = 0;i <= x;i++) { for (int j = 0;j <= y;j++) { dp[i + 1][j] += dp[i][j] / 2; dp[i][j + 1] += dp[i][j] - dp[i + 1][j]; } } return dp[x][y]; } bool solve() { ll t; int x, y; cin >> t >> x >> y; cout << (get(t, x, y) - get(t - 1, x, y) ? "YES" : "NO") << '\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; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16755843.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧