日常训练2025-1-22
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-21
16.日常训练2025-1-22
17.日常刷题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-22
F Tokitsukaze and Eliminate (hard)
思路(小巧思)
标准的Trick题,构造一个样例来模拟一下会发现,在删的那个数的位置之后的每一种数都至少出现了一次,他是最后出现的。模拟这个过程就行。
代码
#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; using namespace std; void solve(){ int n; cin>>n; vector<int>a(n+1); map<int,int>mp1,mp2; for(int i=1;i<=n;i++){ cin>>a[i]; mp1[a[i]]++; } int pos=mp1.size(); int ans=0; for(int i=n;i>=1;i--){ if(mp1.size()==1){ ans+=i; break; } mp2[a[i]]++; mp1[a[i]]--; if(mp1[a[i]]==0) mp1.erase(a[i]); if(mp2.size()==pos){ ans++; mp2.clear(); pos=mp1.size(); } } cout<<ans<<endl; } 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; }
Tokitsukaze and Slash Draw
思路(最短路)
将题目的模型建出来发现其实就是一个图。我们跑一个 Dij 算法即可。
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int tc; cin >> tc; while (tc--) { int n, m, k; cin >> n >> m >> k; vector a(m, 0), b(n, 0); for (int i = 0; i < m; i++) { cin >> a[i] >> b[i]; } std::vector<int> vis(n); vector dp(n, -1ll); dp[k % n] = 0; priority_queue<int, std::vector<int>, std::greater<>> q; q.push(k % n); while (q.size()) { int u = q.top(); q.pop(); if (vis[u]) continue; vis[u] == 1; for (int i = 0; i < m; i++) { int v = (u + a[i]) % n; if (dp[v] == -1 || dp[v] > dp[u] + b[i]){ dp[v] = dp[u] + b[i]; if (vis[v] == 0) q.push(v); } } } // for (int i = 0; i < n; i++) { // cerr << dp[i] << ' '; // } cout << dp[0] << '\n'; } return 0; }
E. Find the Car
rating:1500
思路(二分)
直接二分找第一个比他大的标志为在哪,然后使用初中计算公式算一下就行了。
代码
#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, k, q; std::cin >> n >> k >> q; std::vector<int> a(k+1), b(k+1); for (int i = 1; i <= k; i++){ std::cin >> a[i]; } for (int i = 1; i <= k; i++){ std::cin >> b[i]; } for (int i = 0; i < q; i++){ int x; std::cin >> x; i64 ans = 0; int idx = std::lower_bound(a.begin(), a.end(), x) - a.begin(); if (idx == 0){ ; }else{ ans = b[idx - 1] + 1LL * (x - a[idx-1]) * (b[idx] - b[idx-1]) / (a[idx] - a[idx-1]); } std::cout << ans << ' '; } 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; }
A. Permutation Counting
rating:1400
思路1(类模拟)
使用模拟的思路计算用k补齐之后,最小值最大能得多少,然后统计答案即可。注意,多出来的 k 和多出来的数都可以额外地贡献答案。
代码1
#include <bits/stdc++.h> using i64 = long long; void solve() { int n; i64 k; std::cin >> n >> k; std::vector<i64> a(n); for (int i = 0; i < n; i++) { std::cin >> a[i]; } std::sort(a.begin(), a.end()); i64 maxx = a[0]; for (int i = 1; i < n; i++){ if (i*(a[i]-a[i-1]) <= k){ k -= i * (a[i] - a[i-1]); maxx = a[i]; }else{ maxx += k / i; k %= i; break; } } i64 ans = maxx * n + k - n + 1; for (int i = 0; i < n; i++){ if (a[i] > maxx){ ans++; } } std::cout << std::max(ans, 0LL) << '\n'; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t; std::cin >> t; while (t--) { solve(); } return 0; }
思路2(二分)
这里用二分找最小值最大能得多少,其他的基本一至。
代码2
#include <bits/stdc++.h> using namespace std; const int maxn = 2e6 + 5; typedef long long ll; typedef pair<ll,ll> pii; ll n, k; ll a[maxn]; bool check(ll x) { ll need = 0; for (int i = 1; i <= n; i++) { if (a[i] < x) need += x - a[i]; } return need <= k; } void solve() { cin >> n >> k; for (int i = 1; i <= n; i++) cin >> a[i]; ll left = 1, right = 2e12; ll mn; // 求能达到的最小值 while (left + 1 < right) { ll mid = (left + right) / 2; if (check(mid)) left = mid; else right = mid; } if (check(right)) mn = right; else mn = left; for (int i = 1; i <= n; i++) { if (a[i] < mn) { ll t = mn - a[i]; a[i] += t, k -= t; } } ll num = 0; for (int i = 1; i <= n; i++) { if (a[i] == mn && k ) a[i]++, k--; if (a[i] > mn) num++; } ll ans = n * (mn - 1) + 1 + num; cout << ans << endl; } //? ? ? 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 int main(){ ios::sync_with_stdio(false); cin.tie(0); int T; cin >> T; while (T--) solve(); }
A. Everything Nim
rating:1400
思路(博弈)
思考一下会发现,当序列中存在1是,只能取1,没有其他办法,如果没有1了,那么此时先手一定必胜。
代码
#include <bits/stdc++.h> using i64 = long long; using namespace std; void solve() { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; i++) cin >> a[i]; sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); n = a.size(); int round = 0; for (int i = n - 1; i > 0; i--) a[i] -= a[i - 1]; reverse(a.begin(), a.end()); while (a.size() && a.back() == 1) { a.pop_back(), round ^= 1; } if (a.size() == 0) round ^= 1; cout << (round ? "Bob" : "Alice") << '\n'; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t; std::cin >> t; while (t--) { solve(); } return 0; }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18685625
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步