voidsolve() { int n, sx, sy, ex, ey; cin >> n >> sx >> sy >> ex >> ey; vector<pii> pt(n); set<int> cnt; for (int i = 0; i < n; i++) { cin >> pt[i].first; cnt.emplace(pt[i].first); } for (int i = 0; i < n; i++) { cin >> pt[i].second; } int lien = cnt.size(); sort(all(pt), [](pii a, pii b) { return a.first < b.first; });
for (int i=1;i<=n;i++) cin>>nums[i]; vi dp(n+1); int ans=-4545556565; for(int j=1;j<=n;j++) { dp[j]=dp[j-1]+nums[j]; if (dp[j]<=0) dp[j]=nums[j]; ans=max(ans,dp[j]); } cout<<ans<<'\n'; }
A. Against the Difference
题目
We define that a block is an array where all elements in it are equal to the length of the array. For example, [3,3,3], [1], and [4,4,4,4] are blocks, while [1,1,1] and [2,3,3] are not.
An array is called neat if it can be obtained by the concatenation of an arbitrary number of blocks (possibly zero). Note that an empty array is always neat.
You are given an array a consisting of n integers. Find the length of its longest neat subsequence∗. ∗A sequence c is a subsequence of a sequence a if c can be obtained from a by the deletion of several (possibly, zero or all) element from arbitrary positions.
我们定义block是一个数组,其中的所有元素都等于该数组的长度。例如, [3,3,3] , [1] 和 [4,4,4,4] 是块,而 [1,1,1] 和 [2,3,3] 不是块。
如果数组可以通过任意数量的块(可能为零)的连接获得,则称为整齐数组。注意,空数组总是整洁的。
给定一个由 n 个整数组成的数组 a 。求它的最长整洁子序列 ∗ 的长度。 ∗ 序列 c 是序列 a 的子序列,如果 c 可以从 a 中删除任意位置的几个(可能为零或全部)元素。
voidsolve() { int n; cin>>n; vi nums(n+1); vector<vi> idx(n+1); vi ery(n+1); rep(i,1,n) { cin>>nums[i]; idx[nums[i]].push_back(i); ery[i]=idx[nums[i]].size(); }
vi dp(n+1); dp[0]=0; vi xz(n+1); for(int i=1;i<=n;i++) { int pans=0; int cur=ery[i]-nums[i]; if(cur>=xz[i]*nums[i]) { pans=dp[idx[nums[i]][cur]-1]+nums[i]; xz[nums[i]]++; } dp[i]=max(pans,dp[i-1]);
vi dp(32,0); int zuida=-1; for (int hsh : nums) { for (int i = 0; i < 32; i++) { if ((hsh >> i) & 1) { zuida=max(dp[i]+1,zuida); } } for (int i = 0; i < 32; i++) { if ((hsh >> i) & 1) { dp[i]=zuida; } } }
voidsolve() { string s; cin >> s; int n = s.size(); vector<vi> dp(n + 1, vi(n + 1, INF));
for (int i = 0; i < n - 1; i++) { if (s[i] == s[i + 1]) { dp[i][i + 1] = 0; } }
for (int len = 1; len <= n; len++) { for (int l = 0; l + len - 1 < n; l++) { int r = l + len - 1; if (r == l) { dp[l][r] = 0; } else { if (s[l] == s[r]) { dp[l][r] = min(dp[l][r], dp[l + 1][r - 1]); }
voidsolve() { int n; cin >> n; vector<vi> dp(n, vi(n, -1)); ll ans = 0; rep(i, 0, n - 1) { cin >> dp[i][i]; ans = max(ans,(ll) dp[i][i]); } // 枚举长度,枚举起点,枚举断点
for (int len = 2; len <= n; len++) { for (int i = 0; i + len - 1 < n; i++) { for (int k = i; k < i + len - 1; k++) { if (dp[i][k] == dp[k + 1][i + len - 1] && dp[i][k] > 0) { dp[i][i + len - 1] = max(dp[i][k] + 1, dp[i][i + len - 1]); ans = max(ans, (ll)dp[i][i + len - 1]); } } } } cout << ans; }
voidsolve() { int n; cin >> n; // vi nums(n); ll ans = 0; vector<vi> dp(61, vi(n + 3, -1)); for (int i = 0; i < n; i++) { int in = 0; cin >> in; dp[in][i] = i + 1; ans = max(ans, (ll)in); }
for (int i = 1; i <= 60; i++) { for (int j = 0; j < n; j++) { if (dp[i][j] == -1) { dp[i][j] = dp[i - 1][dp[i - 1][j] + 1]; } if (dp[i][j] != -1) { // dp[i][j]=dp[i][dp[i-1][j]+1]; // dp[i][j]=dp[i][dp[i-1][j]+1]; ans = max((ll)i, ans); } } }
思维误区 (Bug):数组开大导致mle,答案数字比较大需要初始化为LINF。注意到必须尽量在魅力值高的时候收集这个彩蛋,而如果一个彩蛋掉入海中,它的魅力值将会变成一个负数,但这并不影响 Sue 兴趣。注意到我们无法贪心的去找到在这段上面消耗的时间(因为有可能往左或者往右,因为是区间dp)。所以我们仅能逆向思路:求“损失最小值”。处理方法前缀和维护“彩球失去的价值”。
voidsolve() { int n, x0; cin >> n >> x0; vector<pt> ptt(n + 3); for (int i = 0; i < n; i++) { cin >> ptt[i].x; } ll sum = 0; for (int i = 0; i < n; i++) { cin >> ptt[i].y; sum += ptt[i].y; }
voidsolve(){ int n, v; cin >> n >> v; structkind { int value, weight; }; vector<kind> nums(n); for (int i = 0; i < n; i++) { cin >> nums[i].weight >> nums[i].value; } vector<int> dp(v + 1); vector<int> dp2(v + 1, -99999999); // 恰好装满 dp2[0] = 0; for (int i = 0; i < n; i++) { for (int j = v; j >= nums[i].weight; j--) { dp[j] = max(dp[j], dp[j - nums[i].weight] + nums[i].value); dp2[j] = max(dp2[j], dp2[j - nums[i].weight] + nums[i].value); } } cout << dp[v] << '\n'; cout << (dp2[v] > 0 ? dp2[v] : 0) << '\n'; }
二维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
voidsolve(){ int t, m; // t=容量, m=物品数 cin >> t >> m; structcy { int time, ac; }; vector<cy> cord(m + 1); for (int i = 1; i <= m; i++) { cin >> cord[i].time >> cord[i].ac; } int dp[105][1005] = {}; for (int i = 1; i <= m; i++) { for (int j = 0; j <= t; j++) { if (j >= cord[i].time) dp[i][j] = max(dp[i-1][j-cord[i].time] + cord[i].ac, dp[i-1][j]); else dp[i][j] = dp[i-1][j]; } } cout << dp[m][t] << '\n'; }
复杂度:
一维:O(n*v),空间 O(v)。
二维:O(nt),空间 O(nt)。
完全背包
用途:物品可无限选,求最大价值。 常见坑:正序循环(区别于 01 背包倒序),防止重复选择。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
voidsolve(){ int time, n; cin >> time >> n; structcy { int t, v; }; vector<cy> hsh(n + 1); for (int i = 1; i <= n; i++) cin >> hsh[i].t >> hsh[i].v; vector<int> dp(time + 1); for (int i = 1; i <= n; i++) { for (int j = hsh[i].t; j <= time; j++) dp[j] = max(dp[j - hsh[i].t] + hsh[i].v, dp[j]); } cout << dp[time] << '\n'; }