日常训练2025-1-16
1.日常刷题2025-3-162.日常训练2025-1-23.日常训练2025-1-34.日常训练2025-1-55.日常训练2025-1-86.日常训练2025-1-117.日常训练2025-1-128.日常训练2025-1-139.日常训练2025-1-1410.日常训练2025-1-15
11.日常训练2025-1-16
12.日常训练2025-1-1713.日常训练2025-1-1814.日常训练2025-1-1915.日常训练2025-1-2116.日常训练2025-1-2217.日常刷题2025-1-2318.日常训练2025-1-2419.日常刷题2025-1-2520.日常刷题21.日常刷题2025-2-622.日常刷题2025-2-923.日常刷题2025-2-1424.日常刷题2025-2-1525.日常刷题2025-2-1726.日常刷题2025-2-2027.日常刷题2025-2-2128.日常刷题2025-2-2229.日常刷题2025-2-2430.日常刷题2025-2-2631.日常刷题2025-2-2732.日常刷题2025-2-2833.日常刷题2025-3-134.日常刷题2025-3-235.日常刷题2025-3-336.日常刷题2025-3-537.日常刷题2025-3-638.日常刷题2025-3-739.日常刷题2025-3-840.日常刷题2025-3-941.日常刷题2025-3-1042.日常刷题2023-3-1143.日常刷题2025-3-1344.非常棒的二分和DP日常训练2025-1-16
C. Add Zeros
rating:1500
思路(转化为图)
我们把公式化成 |a| = a_i + i - 1,即满足这个公式的位置会给长度加 i - 1
所以相当于从 a_i + i - 1 ----> a_i + i - 1 + i - 1 建一条有向边,跑一个 dfs 即可。
评述
写dfs,和bfs的时候一定要写vis数组,千万别相信愚蠢的直觉。
代码
#include <bits/stdc++.h> typedef std::pair<long long, long long> pll; typedef std::pair<int, int> pii; #define INF 0x3f3f3f3f #define MOD 998244353 using i64 = long long; const int N = 1e5+5; void solve(){ int n; std::cin >> n; std::map<i64, bool> vis; std::map<i64, std::vector<i64>> mp; std::vector<i64> a(n+1); for (int i = 1; i <= n; i++){ std::cin >> a[i]; mp[a[i]+i-1].emplace_back(a[i]+2*(i-1)); } i64 ans = n; auto dfs = [&](auto self, i64 p) -> void { vis[p] = 1; ans = std::max(ans, p); for (auto to : mp[p]){ if (!vis[to]){ self(self, to); } } }; dfs(dfs, n); std::cout << ans << '\n'; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2); int t = 1, i; std::cin >> t; for (i = 0; i < t; i++){ solve(); } return 0; }
D. Robert Hood and Mrs Hood
rating:1400
思路(滑动窗口)
滑动窗口算法是在给定窗口大小的数组或字符串上统计窗口内部数据的操作。这道题给定了窗口大小是d,然后只需统计窗口内重叠的工作数量就行。r 表示窗口的头部,只负责添加重叠,l 表示窗口的尾部,只负责减少重叠。
代码
#include <bits/stdc++.h> typedef std::pair<long long, long long> pll; typedef std::pair<int, int> pii; #define INF 0x3f3f3f3f #define MOD 998244353 using i64 = long long; const int N = 1e5+5; void solve(){ int n, d, k; std::cin >> n >> d >> k; std::map<int, int> mp; std::map<int, int> dic; for (int i = 0; i < k; i++){ int u, v; std::cin >> u >> v; mp[u]++; dic[v]++; } int ans1 = -1, ans2 = -1; int maxx = 0; int minn = INT_MAX; int cur = 0; int l = 0, r = 0; while (r < n){ r++; if (mp[r] != 0){ cur += mp[r]; } if (r - l + 1 > d){ l++; if (dic[l-1] != 0){ cur -= dic[l-1]; } } if (l >= 1 && r - l + 1 == d){ if (cur > maxx){ maxx = cur; ans1 = l; } if (cur < minn){ minn = cur; ans2 = l; } } } std::cout << ans1 << ' ' << ans2 << '\n'; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2); int t = 1, i; std::cin >> t; for (i = 0; i < t; i++){ solve(); } return 0; }
E. Klee's SUPER DUPER LARGE Array!!!
rating:1400
思路(二分)
答案只有两种情况,分界线左边刚好大于分界线右边,此时的答案是最小正数,还有就是分界线左边刚好分界线右边,此时答案是最大的负数。
所以我们可以根据二分找到最小的正数的分界线在哪,此分界线+1就是最大负数的分界线了。
代码
#include <bits/stdc++.h> typedef std::pair<long long, long long> pll; typedef std::pair<int, int> pii; #define INF 0x3f3f3f3f #define MOD 998244353 using i64 = long long; const int N = 1e5+5; void solve(){ i64 n, k; std::cin >> n >> k; i64 sum = n * (k + k + n - 1) / 2; i64 ans = sum; i64 lo = 0, hi = n; while (lo < hi){ i64 x = (lo + hi + 1) / 2; i64 s = x * (k + k + x - 1) / 2; if (s <= (sum - s)){ lo = x; }else{ hi = x - 1; } } for (auto x : {lo, lo + 1}){ if (x > n) continue; i64 s = x * (k + k + x - 1) / 2; ans = std::min(ans, abs(s - (sum - s))); } std::cout << ans << '\n'; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2); int t = 1, i; std::cin >> t; for (i = 0; i < t; i++){ solve(); } return 0; }
C. Guess The Tree
rating:1500
思路(模拟)
题目中给的那个公式,返回一个 x, 这个 x 其实就是 a b 的中点,所以相当于是二分操作。
模拟一下就能发现,随便拿两个节点 a b,a节点不变,b 节点不断换成询问后的回答节点 c,这样一定能找到 a 节点的一条边。n 的上界是1000,就算这颗二叉树是一条链(存在两节点距离最远)的情况下,也可以通过10次查找找出来这条边(2^10 > 1000),所以直接暴力找即可。
代码
#include <bits/stdc++.h> typedef std::pair<long long, long long> pll; typedef std::pair<int, int> pii; #define INF 0x3f3f3f3f #define MOD 998244353 using i64 = long long; const int N = 1e5+5; void solve(){ int n; std::cin >> n; auto ask = [&](int a, int b) ->int{ printf("? %d %d\n", a, b); fflush(stdout); int ret; scanf("%d", &ret); return ret; }; std::vector<int> fa(n+1); for (int i = 2; i <= n; i++){ int r = 1; // j < 10 就够用了,开15豪横。 for (int j = 0; j < 15; j++){ int g = ask(i, r); if (g == i) break; r = g; } fa[i] = r; } printf("!"); for (int i = 2; i <= n; i++){ printf(" %d %d", fa[i], i); } puts(""); fflush(stdout); } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2); int t = 1, i; std::cin >> t; for (i = 0; i < t; i++){ solve(); } return 0; }
D - Strange Mirroring
rating:青色
思路(思维题)
能想到二进制简直太强。
评述
非常棒的思维题
代码
#include <bits/stdc++.h> typedef std::pair<long long, long long> pll; typedef std::pair<int, int> pii; #define INF 0x3f3f3f3f #define MOD 998244353 using i64 = long long; const int N = 1e5+5; void solve(){ std::string s; std::cin >> s; int len = s.size(); auto C = [&](char x) -> char{ if (x >= 'A' && x <= 'Z') return x - 'A' + 'a'; else return x - 'a' + 'A'; }; int n; std::cin >> n; for (int i = 0; i < n; i++){ i64 x; std::cin >> x; x--; if (__builtin_popcountll(x / len) & 1) std::cout << C(s[x % len]) << ' '; else std::cout << s[x%len] << ' '; } } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2); int t = 1, i; for (i = 0; i < t; i++){ solve(); } return 0; }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18674736
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步