日常训练2025-1-8
1.日常刷题2025-3-162.日常训练2025-1-23.日常训练2025-1-34.日常训练2025-1-5
5.日常训练2025-1-8
6.日常训练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-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-8
E小红的双生英雄
思路
读题后跟容易发现是一道分组背包的题,转移也比较简单。有一个做动态规划题的技巧是,如果题目相较于传统的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 = 1e5+5; void solve(){ int n, C, m; std::cin >> n >> C >> m; std::vector<pll> tmp(n+1); std::vector<bool> st(n+1); for (int i = 1; i <= n; i++) { int cost, v; std::cin >> cost >> v; tmp[i] = pll(cost, v); } std::vector<std::vector<pll>> a; for (int i = 0; i < m; i++){ int u, v, w; std::cin >> u >> v >> w; st[u] = st[v] = true; a.push_back({tmp[u], tmp[v], {tmp[u].first + tmp[v].first, tmp[u].second + tmp[v].second + w}}); } for (int i = 1; i <= n; i++){ if (!st[i]) a.push_back({tmp[i]}); } std::vector<std::vector<i64>> dp(C+1, std::vector<i64>(5)); std::vector<std::vector<i64>> ndp(C+1, std::vector<i64>(5)); for (auto s : a){ ndp = dp; for (int i = 0; i < s.size(); i++){ auto [cost, atk] = s[i]; int ok = i == 2; for (int j = C; j >= cost; j--){ for (int k = 4; k >= 1 + ok; k--){ dp[j][k] = std::max(dp[j][k], ndp[j-cost][k-1-ok] + atk); } } } } i64 ans = 0; for (int j = 0; j <= C; j++){ for (int k = 0; k <= 4; k++){ ans = std::max(ans, dp[j][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; for (i = 0; i < t; i++){ solve(); } return 0; }
D.Repeated Sequence
rating:800
思路
思考得到,和为 s 的序列由三部分组成:1.一个后缀,2.若干个完整的循环,3.一个前缀。(特殊情况是,连一个完整的循环都没有)。由数学常识可以知道,后缀+前缀的和为 s % sum。
所以本题就是是否存在一个前缀和后缀的和为 s % sum
可以把原序列向后复制一份。然后然后答案就是一个跨越中点的序列的和为 s % sum。当序列不跨越中点时则刚好是特殊情况的时候。
代码
#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, s; std::cin >> n >> s; i64 sum = 0; std::vector<i64> v((n+1) * 2); for (int i = 1; i <= n; i++) { std::cin >> v[i]; v[i+n] = v[i]; } std::vector<i64> pre((n+1)*2); for (int i = 1; i <= n*2; i++){ pre[i] = pre[i-1] + v[i]; } s %= pre[n]; if (s == 0){ std::cout << "Yes\n"; return; } std::set<i64> st; for (int r = 1; r <= 2*n; r++){ if (st.count(pre[r] - s)){ std::cout << "Yes\n"; return; } st.insert(pre[r]); } std::cout << "No\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/18660337
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步