CodeTON Round 2 (Div. 1 + Div. 2, Rated, Prizes!) A-E
A
题解
知识点:思维,模拟。
发现 串第一个字符是 则只能使用 max
, 则只能使用 min
,随后只需要模拟到 串剩余 个字符时停止即可,然后比对两串。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; bool solve() { int n, m; cin >> n >> m; string a, b; cin >> a >> b; if (b[0] == '0') for (int i = 1;i <= n - m;i++) a[i] = min(a[i], a[i - 1]); else if (b[0] == '1') for (int i = 1;i <= n - m;i++) a[i] = max(a[i], a[i - 1]); if (a.substr(n - m, m) == b) return true; else return false; } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t = 1; cin >> t; while (t--) { if (!solve()) cout << "NO" << '\n'; else cout << "YES" << '\n'; } return 0; }
B
题解
知识点:贪心。
一个一个走过去,记录走过的最大值和最小值,一旦大于两倍 则说明要换中心点 ,记录换的次数即可。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; bool solve() { int n, x; cin >> n >> x; int mi = 2e9, mx = 0, cnt = 0; for (int i = 1, tmp;i <= n;i++) { cin >> tmp; mi = min(mi, tmp); mx = max(mx, tmp); if (mx - mi > 2 * x) cnt++, mx = mi = tmp; } cout << cnt << '\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
题解
知识点:贪心。
注意到所有非感染者区间每秒都会被感染两个(从左右端点扩展,少于两个直接消失),因此考虑从大区间端点开始保护,每次更新 代表每个区间减少了多少,则真实区间长度是原长减去 。
因此若真实区间大于等于2,则在两个端点各保护一个,答案加区间长度减一(一个端点保护完,另一个端点会感染一个), 加 ;若区间长度等于1,则只能保护一个,直接退出;若区间已经小于等于0,没有能保护的,直接退出。
代码
#include <bits/stdc++.h> #define ll long long using namespace std; int a[100007], l[100007]; bool solve() { int n, m; cin >> n >> m; for (int i = 1;i <= m;i++) cin >> a[i]; sort(a + 1, a + 1 + m); l[1] = n - (a[m] - a[1] + 1); for (int i = 2;i <= m;i++) l[i] = a[i] - a[i - 1] - 1; sort(l + 1, l + m + 1, [&](int a, int b) {return a > b;}); int delta = 0, ans = 0; for (int i = 1;i <= m;i++) { int rl = max(l[i] - delta, 0); if (rl == 0) break; if (rl == 1) { ans++; break; } ans += rl - 1; delta += 4; } cout << n - 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
题解
知识点:枚举,前缀和,思维。
通常这种题是找不变量。
发现经过操作1以后,前缀和的总和不变;而经过一次操作2后,前缀和的总和会减少1。
因此统计每个数组的前缀和总和,找到前缀和总和最小的就是特殊数组,少了多少就是操作了多少次。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; ll ssum[100007]; bool solve() { int n, m; cin >> n >> m; for (int i = 1;i <= n;i++) { ll sum = 0; ssum[i] = 0; for (int j = 1;j <= m;j++) { ll x; cin >> x; sum += x; ssum[i] += sum; } } cout << min_element(ssum + 1, ssum + n + 1) - ssum << ' '; cout << *max_element(ssum + 1, ssum + n + 1) - *min_element(ssum + 1, ssum + n + 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。
题目不难理解为,每秒所有点都会流出一个量到所有自己的下一个点,什么时候流完。比如,若 有三个下一个节点 ,则一秒后 的值减一,而 都加一。
因为是DAG,所以图中每个点的量总是向出度为 的节点方向流动,最终出度为 的点的流完时间就是答案。
而对于一个节点的流完时间,取决于他所有上一个节点流完时间的总和加上自己节点的量,因为一个节点每秒只能流出一个量,只要上一个节点没流完,那这个节点就会一直存在量。因此,设 为编号 的节点的流出时间,则节点 与其上一个节点 有转移方程:
但是有一种情况,如 10-0-1-0-0-null
,显然流完时间是 ,但通过上面计算得到的是 。因为上述方程直接考虑从第一秒到最后一秒,整个图的量的转移是连续的,即量是持续减少,而没有考虑中间可能存在断点,但显然这是不确定的,这个例子就是。
因此需要使整个图的量堆积在出口前,使得量的流出是连续的。由于整个图有 个节点,至多 秒可以让量流经图中所有点(这里模拟 秒都没问题),因此先模拟 秒,等到量都连起来了,再dp计算总时间即可。
模拟时候用正图,dfs时候反图,因此存两个图。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; const int mod = 998244353; vector<int> a, dp; vector<int> g1[1007], g2[1007]; ///g1正向模拟用,g2反向dfs用 int dfs(int u) { if (dp[u]) return dp[u]; dp[u] = a[u] % mod; for (auto v : g2[u]) dp[u] = (0LL + dp[u] + dfs(v)) % mod; return dp[u]; } bool solve() { int n, m; cin >> n >> m; a = dp = vector<int>(n + 1, 0); for (int i = 1;i <= n;i++) cin >> a[i], g1[i].clear(), g2[i].clear(); for (int i = 1;i <= m;i++) { int u, v; cin >> u >> v; g1[u].push_back(v); g2[v].push_back(u); } if (count(a.begin() + 1, a.end(), 0) == n) { cout << 0 << '\n'; return true; } for (int i = 1;i <= n;i++) {///保证所有量都在出口前靠拢,防止空节点挡在其他节点之前产生计算错误 vector<int> t = a;///临时,防止某个量持续传递 for (int u = 1;u <= n;u++) { if (a[u]) { t[u]--; for (auto v : g1[u]) t[v]++; } } a = t; if (count(a.begin() + 1, a.end(), 0) == n) { cout << i << '\n'; return true; } } int root = 0; for (int i = 1;i <= n;i++) if (!g1[i].size()) root = i; cout << (dfs(root) + n) % mod << '\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/16547850.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧