日常训练2025-1-17
1.日常刷题2025-3-82.日常训练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-16
12.日常训练2025-1-17
13.日常训练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-7日常训练2025-1-17
rating:1500
思路(裴蜀定理)
碰到要么加a 要么加 b 的题一定要想到裴蜀定理, ax + by = gcd(a, b)。即每个数可以加减k*gcd(a, b)。
所以我们可以把每个数都调整到只相差小于gcd(a, b)的范围内。这样会贡献一次答案。
然后每个数都可以做一次最大值和最小值,枚举一遍再求答案即可。
代码
#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, a, b; std::cin >> n >> a >> b; int d = std::gcd(a, b); std::vector<int> v(n); for (int i = 0; i < n; i++){ std::cin >> v[i]; v[i] %= d; } std::sort(v.begin(), v.end()); int ans = v[n-1] - v[0]; for (int i = 1; i < n; i++){ ans = std::min(ans, v[i-1]+d-v[i]); } 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. Maximize the Root
rating:1500
思路(树形DP)
明显不能贪心。考虑 dp。
我们要让根节点尽可能大,那么就要让根节点能进行的操作数尽可能多。
而操作数取决于子树中权值最小的点的权值。
令
转移时,令 mn 为 x 的儿子节点的 dp 值的最小值,分类讨论:
- mn<ax。此时操作只会让最小值更小。
- mn≥ax。此时我们可以操作直到 mn≤ax,这样最小值会变大。
注意我们是要让根节点权值最大,所以在根节点上不需要考虑子树最小值最大,直接无脑操作即可。
代码
#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<i64> b(n+1, 0); std::vector<i64> fa(n+1, 0); std::vector g(n+1, std::vector<i64>()); std::vector<i64> a(n+1, 0); for (int i = 1; i <= n; i++) std::cin >> a[i]; for (int i = 2; i <= n; i++){ std::cin >> fa[i]; g[fa[i]].push_back(i); g[i].push_back(fa[i]); } auto dfs = [&](auto self, i64 cur) -> void { i64 minn = 1000000001; for (auto to : g[cur]){ if (to == fa[cur]) continue; self(self, to); minn = std::min(minn, b[to]); } if (minn == 1000000001){ b[cur] = a[cur]; return; } if (cur == 1){ a[cur] += minn; return; } if (a[cur] < minn) b[cur] = (a[cur] + minn) / 2; else b[cur] = minn; }; dfs(dfs, 1); std::cout << a[1] << '\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. Have Your Cake and Eat It Too
rating:1400
思路(暴力枚举)
首先 3! 枚举下从前往后的每一段分别是由哪个人拿走
通过
two pointers
枚举中间那段的极小的合法区间,然后检验前后缀是否合法即可
代码
#include<bits/stdc++.h> using namespace std; #define int long long signed main() { int t; cin>>t; while(t--) { int n; cin >> n; int a[n+1], b[n+1], c[n+1]; int sum = 0; for(int i = 1;i<=n;i++) { cin >> a[i]; sum += a[i]; } sum = (sum+2)/3;//题中说了上限除法 for(int i = 1;i<=n;i++) { cin >> b[i]; } for(int i = 1;i<=n;i++) { cin >> c[i]; } vector<int> p1(n+5), p2(n+5), p3(n+5);//正序前缀和 vector<int> s1(n+5), s2(n+5), s3(n+5);//倒序前缀和 for(int i = 1; i <= n; i++) { p1[i] = p1[i-1] + a[i]; p2[i] = p2[i-1] + b[i]; p3[i] = p3[i-1] + c[i]; } for(int i = n; i >= 1; i--) { s1[i] = s1[i+1] + a[i]; s2[i] = s2[i+1] + b[i]; s3[i] = s3[i+1] + c[i]; } //a b c int i = 1, j = n; while(p1[i-1] < sum && i <= n) { i++; } while(s3[j+1] < sum && j >= 1) { j--; } if(i <= j && p2[j]-p2[i-1] >= sum) { cout << 1 << ' ' << i-1 << ' ' << i << ' ' << j << ' ' << j+1 << ' ' << n << endl; continue; } // a c b i = 1, j = n; while(p1[i-1] < sum && i <= n) { i++; } while(s2[j+1] < sum && j >= 1) { j--; } if(i <= j && p3[j]-p3[i-1] >= sum) { cout << 1 << ' ' << i-1 << ' ' << j+1 << ' ' << n << ' ' << i << ' ' << j << endl; continue; } // b c a i = 1, j = n; while(p2[i-1] < sum && i <= n) { i++; } while(s1[j+1] < sum && j >= 1) { j--; } if(i <= j && p3[j]-p3[i-1] >= sum) { cout << j+1 << ' ' << n << ' ' << 1 << ' ' << i-1 << ' ' << i << ' ' << j << endl; continue; } // b a c i = 1, j = n; while(p2[i-1] < sum && i <= n) { i++; } while(s3[j+1] < sum && j >= 1) { j--; } if(i <= j && p1[j]-p1[i-1] >= sum) { cout << i << ' ' << j << ' ' << 1 << ' ' << i-1 << ' ' << j+1 << ' ' << n << endl; continue; } // c a b i = 1, j = n; while(p3[i-1] < sum && i <= n) { i++; } while(s2[j+1] < sum && j >= 1) { j--; } if(i <= j && p1[j]-p1[i-1] >= sum) { cout << i << ' ' << j << ' ' << j+1 << ' ' << n << ' ' << 1 << ' ' << i-1 << endl; continue; } // c b a i = 1, j = n; while(p3[i-1] < sum && i <= n) { i++; } while(s1[j+1] < sum && j >= 1) { j--; } if(i <= j && p2[j]-p2[i-1] >= sum) { cout << j+1 << ' ' << n << ' ' << i << ' ' << j << ' ' << 1 << ' ' << i-1 << endl; continue; } cout << -1 << endl; } return 0; }
D. GCD-sequence
rating:1400
思路(暴力枚举)
这种操作后只会使小范围内的关系发生变化的题一般都是暴力枚举操作位置。
一个数被删除只会使相邻的逆序关系的减少和新的逆序关系的增加,对其他位置没有影响。所以我们只需要暴力枚举每个数被删除的时候的情况满不满足题意。
代码
#include <bits/stdc++.h> using i64 = long long; void solve() { int n; std::cin >> n; std::vector<int> a(n); for (int i = 0; i < n; i++) { std::cin >> a[i]; } std::vector<int> b(n - 1); for (int i = 0; i < n - 1; i++) { b[i] = std::gcd(a[i], a[i + 1]); } int bad = 0; for (int i = 1; i < n - 1; i++) { bad += b[i] < b[i - 1]; } int ans = 0; if (bad - (b[1] < b[0]) == 0) { ans = 1; } if (bad - (b[n - 2] < b[n - 3]) == 0) { ans = 1; } for (int i = 1; i < n - 1; i++) { int tmp = bad; tmp -= b[i] < b[i - 1]; int g = std::gcd(a[i - 1], a[i + 1]); if (i - 1 > 0) { tmp -= b[i - 1] < b[i - 2]; tmp += g < b[i - 2]; } if (i + 1 < n - 1) { tmp -= b[i + 1] < b[i]; tmp += b[i + 1] < g; } if (tmp == 0) { ans = 1; } } if (ans) { std::cout << "YES\n"; } else { std::cout << "NO\n"; } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t; std::cin >> t; while (t--) { solve(); } return 0; }
C猪猪养成计划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, q; std::cin >> n >> q; std::vector<int> vis(n+1), next(n+1); int cnt = 0; for (int i = 0; i < q; i++){ int key; std::cin >> key; if (key == 1){ int l, r; std::cin >> l >> r; int i = l; while (i <= r){ if (vis[i] != 0) i = next[i]; else{ vis[i] = ++cnt; next[i] = r+1; i++; } } }else{ int x; std::cin >> x; std::cout << vis[x] << '\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; for (i = 0; i < t; i++){ solve(); } return 0; }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18676644
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步