Codeforces 777 题目研讨
本文将研讨 Codeforces 777(Codeforces Round 401 (Div. 2))中的题目 A-E。
题目连接
题目分析
A
难度:普及−
题面翻译:
给你三张牌:
, , 。
最初选一张,然后依次进行次交换,交换规则为:中间一张和左边的一张,中间一张和右边一张,中间一张和左边一张……
最后问选的那张在哪个位置。
算法标签:模拟、枚举、构造、数学
题解:
注意到每
B
难度:普及−
题面翻译:
有两个人 S 和 M,他们每人有一段长度为
的数字,两个人在每一轮游戏中都可以按顺序拿出一个数字,谁的数字小谁就接受一次惩罚。若相等两者都没有惩罚。另外,M 可以重新安排自己数字的顺序,问 M 的最少被惩罚次数和 S 的最多被惩罚次数是多少。
算法标签:博弈论、数据结构、贪心、排序
题解:
先排个序。
参考这个博弈论的现实应用,可以得出以下策略:
- 若此轮能赢,则使用最小的能赢下来的牌。
- 若此轮不能赢,则出当前最小的牌。
证明略。
设 S 的牌为
而对于第二问,出牌条件改为
C
难度:普及+/提高
题面翻译:
给出一个
的矩阵。对于第 列,如果满足 ,则称这一列是不下降的。
次询问,问如果只保留矩阵的第 ~ 行,矩阵中是否存在不下降的一列。
算法标签:二分、数据结构、动态规划、贪心、双指针
题解:
注意到本题和最长不下降子串有关。用
#include <bits/stdc++.h> using namespace std; int n, m, k, a[200010], b[200010], c[200010]; int coordinate(int x, int y) { return x * m + y; } int main() { memset(c, 0x3f, sizeof(c)); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { scanf("%d", &a[coordinate(i, j)]); } } for (int j = 1; j <= m; j++) { for (int i = 1; i <= n; i++) { b[coordinate(i, j)] = ((a[coordinate(i, j)] < a[coordinate(i - 1, j)]) ? i : b[coordinate(i - 1, j)]); } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { c[i] = min(c[i], b[coordinate(i, j)]); } } scanf("%d", &k); while (k--) { int l, r; scanf("%d%d", &l, &r); if (c[r] <= l) puts("Yes"); else puts("No"); } return 0; }
D
难度:普及+/提高
题面翻译:
给出
个开头是 #
的字符串,你需要通过操作使这些字符串按字典序从小到大排列。
每次操作,你可以把某一个字符串的任意后缀去掉(当然你甚至可以去掉整个字符串),要求你去掉的字符数量最少。
输出你操作完的这个字符串。
算法标签:二分、贪心、字符串
题解:
不难发现,本题和排序没有任何关系。
注意到去除后缀会使字符串的字典序变小,因此
#include <bits/stdc++.h> using namespace std; int n; string s[500010]; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n; for (int i = 1; i <= n; i++) cin >> s[i]; for (int i = n - 1; i >= 1; i--) { int t = -1; for (int j = 0; j < s[i].size(); j++) { if (j == s[i + 1].size()) { t = j; break; } if (s[i][j] < s[i + 1][j]) break; if (s[i][j] > s[i + 1][j]) { t = j; break; } } if (t != -1) s[i].erase(t); } for (int i = 1; i <= n; i++) cout << s[i] << "\n"; return 0; }
E
难度:提高+/省选−
题面翻译:
给出
个环形零件的厚度、内径、外径,要求按以下条件装配若干圆盘后,形成的塔最高。
- 圆盘应平放。也就是说,对于每个安放的零件,侧视图应当为长方形,而俯视图应为圆环。
- 圆盘应叠放,而下方的圆盘外径应大于等于上方圆盘的外径。
- 上方圆盘的外径应严格大于下方圆盘的内径(否则上方圆盘会因重力作用掉到下方圆盘的孔里)。
算法标签:枚举、排序
题解:
这道题和最长上升子序列有点像。先按照
设
。于是你 T 了。
因此考虑引入堆优化。将先前的状态压入大根堆中(按
时间复杂度
#include <bits/stdc++.h> using namespace std; #define int long long struct dat { int a, b, h; } ring[100010]; int n, dp[100010]; bool cmp(dat a, dat b) { if (a.b != b.b) return a.b > b.b; return a.a > b.a; } bool operator < (dat x, dat y) { return x.h < y.h; } priority_queue<dat> q; signed main() { scanf("%lld", &n); for (int i = 1; i <= n; i++) { scanf("%lld%lld%lld", &ring[i].a, &ring[i].b, &ring[i].h); } sort(ring + 1, ring + n + 1, cmp); q.push({0, 0, 0}); long long ans = 0; for (int i = 1; i <= n; i++) { while (q.top().a >= ring[i].b) q.pop(); dp[i] = q.top().h + ring[i].h; q.push({ring[i].a, ring[i].b, q.top().h + ring[i].h}); ans = max(ans, dp[i]); } printf("%lld\n", ans); return 0; }
总结
这套题在 Codeforces 中属于较简单水平,有希望考场 AK(只是有希望)。
本文来自博客园,作者:cwkapn,转载请注明原文链接:https://www.cnblogs.com/chenaknoip/p/18538882
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)