寒假思维训练计划day4

又来还债啦,每日一更,今天两更。

  • 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 
#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 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;
}	
 
  

你可能感兴趣的:(算法,c++,数据结构)