日常训练2025-1-14
1.日常刷题2025-3-162.日常训练2025-1-23.日常训练2025-1-34.日常训练2025-1-55.日常训练2025-1-86.日常训练2025-1-117.日常训练2025-1-128.日常训练2025-1-13
9.日常训练2025-1-14
10.日常训练2025-1-1511.日常训练2025-1-1612.日常训练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-14
C. MEX Cycle
rating:1500
思路
注意这是一道构造题。
用xy将环分成两段,为保证xy符合条件,要先给xy的权值设置成01,然后根据两段链的长度的奇偶有两种填数方案。偶数直接01填,奇数要先填一个2然后再随机填。
评述
代码写到红温
代码
#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, x, y; std::cin >> n >> x >> y; std::vector<int> v(n+1, -1); v[x%n] = 1, v[y%n] = 0; if ((y - x - 1) % 2 == 1){ v[x+1] = 2; for (int i = y - 1; i > x + 1; i--){ v[i] = v[(i+1)%n] ^ 1; } }else{ for (int i = y - 1; i > x; i--){ v[i] = v[(i+1)%n] ^ 1; } } if ((n - (y - x + 1)) % 2 == 0){ for (int i = (y + 1) % n, j = 0; j < (n - (y-x+1)); j++, i++, i %= n){ v[i] = v[(i+n-1)%n] ^ 1; } }else{ v[(x+n-1)%n] = 2; for (int i = (y + 1) % n, j = 0; j < (n-(y-x+1))-1; j++, i++, i %= n){ v[i] = v[(i+n-1)%n] ^ 1; } } for (int i = 1; i < n; i++){ std::cout << v[i] << ' '; } std::cout << v[0] << ' '; std::cout << '\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. Sums on Segments
rating:1600
思路(子数组和的最大值和最小值+Trick)
假设题目中没有出现特殊数字,那么答案就是子数组最大值和子数组最小值,以及它们范围中的所有整数,因为序列中只有1或者-1。
假设题目中出现了特殊数字,那么答案分为两部分:
- 不需要加上特殊数字也能得到的数:即是特殊数字左右的子数组最小值,和特殊数字左右的子数组最大值,以及两个最值中间的每个数。
- 加上特殊数字的话:就是求特殊数字左边的数组的包含特殊数字的子数组最大值和最小值,以及特殊数字右边的数组的包含特殊数字的子数组最大值和最小值,最后统计范围中的数。
评述
当数组中的增量是-1和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(){ int n, num = -1; std::cin >> n; std::set<int> ret; std::vector<int> v(n+1); for (int i = 1; i <= n; i++) { std::cin >> v[i]; if (v[i] != -1 && v[i] != 1){ num = i; } } int cntmax = 0; int cntmin = 0; int minn = 0; int maxn = 0; if (num == -1){ for (int i = 1; i <= n; i++){ cntmax += v[i]; cntmin += v[i]; minn = std::min(cntmin, minn); maxn = std::max(cntmax, maxn); if (cntmax < 0) cntmax = 0; if (cntmin > 0) cntmin = 0; } }else{ for (int i = 1; i <= num - 1; i++){ cntmax += v[i]; cntmin += v[i]; minn = std::min(minn, cntmin); maxn = std::max(maxn, cntmax); if (cntmax < 0) cntmax = 0; if (cntmin > 0) cntmin = 0; } cntmax = 0; cntmin = 0; for (int i = num + 1; i <= n; i++){ cntmax += v[i]; cntmin += v[i]; minn = std::min(minn, cntmin); maxn = std::max(maxn, cntmax); if (cntmax < 0) cntmax = 0; if (cntmin > 0) cntmin = 0; } } for (int i = minn; i <= maxn; i++) ret.insert(i); int ans = 0; int premax = 0; int premin = 0; int endmax = 0; int endmin = 0; if (num != -1){ for (int i = num - 1; i >= 1; i--){ ans += v[i]; premax = std::max(premax, ans); premin = std::min(premin, ans); } ans = 0; for (int i = num + 1; i <= n; i++){ ans += v[i]; endmax = std::max(endmax, ans); endmin = std::min(endmin, ans); } for (int i = v[num] + premin + endmin; i <= v[num] + premax + endmax; i++){ ret.insert(i); } } std::cout << ret.size() << '\n'; for (auto e : ret) std::cout << e << ' '; std::cout << '\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; }
B. Move Back at a Cost
rating:1600
思路(贪心+优先级队列)
贪心的想,为了使最后的词典序最小,肯定是数字越小的放越前面。考虑到,当一个小的数字被拿到前面时,它的左边的所有数字都会被+1,并且塞到最后。所以我们用一个变量 pos 记录上一个被拿到前面的数字的最大下标是多少,后续拿出来的每一个数只要下标小于 pos ,则说明一定被操作过,则数值+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(){ int n; std::cin >> n; std::vector<int> a(n+1); std::priority_queue<pii, std::vector<pii>, std::greater<> > q; for (int i = 1; i <= n; i++){ std::cin >> a[i]; q.push({a[i], i}); } int pos = 0; int cnt = n; while (!q.empty()){ auto [x, y] = q.top(); q.pop(); if (y < pos){ q.push({x+1, ++cnt}); }else{ pos = std::max(pos, y); std::cout << x << ' '; } } std::cout << '\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; }
G. Natlan Exploring
rating:2000
思路(容斥优化+计数DP)
经典求路径数目的计数DP,不过这道题核心考点是DP优化,容斥优化DP
评述
利用线性筛是可以求每个数的最小质因子的,可以通过这样的方式优化质因数分解。
代码
#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 = 1e6+5; int sum[N];// 标记位置 std::vector<int> prime;//质数数组 std::vector<int> S(N); void op(int n) { sum[1] = 1; for (int i = 2; i <= n; i++) { if (!sum[i]) prime.push_back(i), sum[i] = i; for (int j : prime) { if (j * i > n) break; sum[j * i] = j; if (i % j == 0) break; } } } void solve(){ int n; std::cin >> n; std::vector<int> a(n+1); std::vector<std::vector<int>> g(n+1, std::vector<int>()); for (int i = 1; i <= n; i++) std::cin >> a[i]; // std::cout << sum[2] << ' ' << sum[6] << ' ' << sum[3] << '\n'; for (int i = 1; i <= n; i++){ int tmp = a[i]; while (tmp != 1){ int v = sum[tmp]; g[i].push_back(v); while(tmp % v == 0) tmp /= v; } } std::vector<int> f(n+1); f[1] = 1; for (int i = 1; i <= n; i++){ int cnt = g[i].size(); std::vector<int> v; for (int j = 1; j < (1 << cnt); j++){ int mul = 1, sgn = -1; for (int k = 0; k < cnt; k++){ if ((j >> k) & 1){ mul *= g[i][k]; sgn *= -1; } } v.push_back(mul); f[i] += sgn * S[mul] % mod; f[i] %= mod; } for (auto e : v){ S[e] += f[i]; S[e] %= mod; } } int ans = (f[n] + mod) % mod; 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); op(N); int t = 1, i; for (i = 0; i < t; i++){ solve(); } return 0; }
D. Sharky Surfing
rating:1400
思路(贪心)
很明显的贪心题,唯一需要注意的是我们是可以回去捡已经跳过的障碍前的能量的。
代码
#include <bits/stdc++.h> #define fi first #define se second #define int long long using namespace std; typedef pair<int, int> PII; typedef long long LL; void solve() { int n, m, L; cin >> n >> m >> L; std::vector<int> l(n), r(n), x(m), v(m); for (int i = 0; i < n; i ++) cin >> l[i] >> r[i]; for (int i = 0; i < m; i ++) cin >> x[i] >> v[i]; multiset<int> up; int E = 1, res = 0; for (int i = 0, j = -1; i < n; i ++) { while (j + 1 < m && x[j + 1] < l[i]) j ++, up.insert(v[j]); while (up.size() && E <= r[i] - l[i] + 1) { E += *up.rbegin(), res ++; up.erase( -- up.end()); } if (E <= r[i] - l[i] + 1) { cout << -1 << endl; return; } } cout << res << endl; } signed main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); int dt; cin >> dt; while (dt --) solve(); return 0; }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18670356
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步