日常刷题2025-1-23
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-1511.日常训练2025-1-1612.日常训练2025-1-1713.日常训练2025-1-1814.日常训练2025-1-1915.日常训练2025-1-2116.日常训练2025-1-22
17.日常刷题2025-1-23
18.日常训练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-23
D. Inaccurate Subsequence Search
rating:1400
思路(定长滑动窗口)
定长滑动窗口,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, m, k; std::cin >> n >> m >> k; std::map<int, int> dic; std::vector<int> a(n), b(m); for (int i = 0; i < n; i++){ std::cin >> a[i]; } for (int i = 0; i < m; i++){ std::cin >> b[i]; dic[b[i]] += 1; } std::map<int, int> mp; int l = 0, r = 0, cnt = 0, ans = 0; while (r < n){ if (dic[a[r]] != 0) { mp[a[r]] += 1; if (mp[a[r]] <= dic[a[r]]) cnt++; } if (r - l + 1 < m) { r++; continue; } ans += cnt >= k; if (dic[a[l]] != 0){ mp[a[l]] -= 1; if (mp[a[l]] < dic[a[l]]) cnt--; } l++; r++; } 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. Ticket Hoarding
rating:1400
思路(贪心)
看着像DP,但是一看 k 的取值范围,DP放弃,只能想一想贪心。如果有一个购买序列b,b任意排序不会影响最终的增量add,因为增加的值是确定的。所以我们可以排序,每次贪心的买价格最少的就行。
代码
#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, m, k; std::cin >> n >> m >> k; std::vector<int> a(n+1); for (int i = 1; i <= n; i++){ std::cin >> a[i]; } std::sort(a.begin() + 1, a.end()); i64 ans = 0, add = 0; for (int i = 1; i <= n; i++){ ans += std::min(m, k) * (a[i] + add); add += std::min(m, k); k -= std::min(m, k); } 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; }
E. Nearly Shortest Repeating Substring
rating:1500
思路(枚举因子+小巧思)
我们先思考一下知道循环长度时答案可能是什么,假设循环长度为 x,答案序列为 k ,则答案一定是 s 字符串开头 x 个或者 s 字符串最后 x 个之一。为什么?
如果开头 x 个不可行,那么说明开头 x 个字符中至少有一个字符与 k 不同,如果最后 x 个也不行,也说明同样的结果,那么如果选开头和选结尾都不行的话,选其他任何的x个字符也一定不行,因为开头和结尾已经各有一个和答案序列不同了。所以 x 这个长度的循环行不行取决为开头和结尾 x 个字符。
那么如何得到 x 呢?
很显然 x 一定只能是 n 的因子,所以我们只需要 log n 的复杂度枚举每一个可行的 x 然后计算是否可行即可。
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 5; vector<int> e[maxn]; int n; string s, t; bool check(int x) { int cnts = 0, cntt = 0; for (int i = x; i < n; i++) { if (s[i % x] != s[i]) cnts++; if (t[i % x] != t[i]) cntt++; } if (cnts <= 1 || cntt <= 1) return true; return false; } void solve() { cin >> n >> s; t = s; reverse(t.begin(), t.end()); vector<int> v; for (int i = 1; i * i <= n; i++) { if (n % i != 0) continue ; v.push_back(n / i); v.push_back(i); } sort(v.begin(), v.end()); for (int i = 0; i < v.size(); i++) { if (check(v[i])) { cout << v[i] << endl; return ; } } } int main() { int T = 1; cin >> T; while (T--) solve(); }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18687116
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步