又来还债啦,每日一更,今天两更。
-
Day4(思维 + 贪心 + 构造)Problem - 1903C - Codeforces
又是一道经典的构造题,前些日子只顾刷题,懒写题解,以前欠的债现在还...(也当做是回顾 题意: 给定一个长度为n的数组,要求将数组分成若干个(>=1)连续的块,使得所有子数组的代价之和最大,代价的计算: [x1,x2,x3],[x4,x5,x6]的计算方法是:(x1+x2+x3)*1 + (x4+x5+x6)*2,也就是sum*i
题解: 这道题要倒着贪,考虑当前i这个位置,后缀和sum + a[i] > 0的时候在此位置分块,后面至少要分>=0的块,此时一定是正的贡献,无论后面是分/不分结果都更好,如果sum + a[i] <= 0的时候此时应该尽量少的加块,从前往后去合并知道sum + a[j] > 0,最后算出答案。
代码:建议只看solve(),主要是贪心策略的去确定,实现起来还是很简单的;
// cpp代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
int n, m;
int a[N];
void solve() {
cin >> n;
int ans = 0;
for(int i = 1; i <= n; i ++ ) cin >> a[i], ans += a[i] * i;
int lsum = 0, cnt = 1, res = 0;
vector<int> us;
a[n + 1] = 0;
for(int i = n,j,s; i >= 1; i -- ) {
lsum += a[i];
if(lsum <= 0) {
j = i, s = a[i];
while(j - 1 >= 1 && lsum <= 0) s += a[j - 1], lsum += a[j - 1], -- j;
us.push_back(s);
i = j;
}
else us.push_back(a[i]);
}
for(int i = us.size() - 1; i >= 0; i -- ) {
// cout << us[i] << endl;
res += us[i] * cnt ++;
}
cout << max(res,ans) << endl;
}
signed main() {
int ts;
cin >> ts;
while(ts--) solve();
return 0;
}