【Educational Codeforces Round 88 (Rated for Div. 2) D】Yet Another Yet Another Task

题目链接

点我吧

题目大意

给你一个长度为n的序列,先手先选择一个区间[L,R], 这个区间里面的数字, 让后手选择一个删掉。

然后计算剩余的R-L个数字的和sum(如果R-L等于0,认为和是0)。

后手总是想让这个sum的值比较低,所以它总是会选择最大的那个数字删掉。

现在让你帮先手选择一个区间,使得这个区间在被后手删掉一个数字之后, 剩余的和最大。

题解

这道题, 如果没有删掉一个数字这个操作的话,就是一个 最大连续和 问题。

不熟悉这个问题的可以看看我 另外一篇文章

大家可能都注意到了, a数组中每个元素最大都只是30。

所以,我们可以先枚举一下最后我们选择的区间里面的最大值ma是多少。

然后,将原数组做一个改动, 把数组当中所有 大于ma的值全都改成负无穷 (其他的保持不变)。

然后在这个改动后的数组里面做最大连续子序列问题,因为比ma大的都变成负无穷了,所以肯定最后

选出来的区间没有大于ma的数字, 这样算出来的 最大连续和减去这个ma 就是最大值为ma的时候,问题的一个可能答案了。

但是大家可能会觉得,那如果选出来的区间中 没有ma这个数字(里面的数字都比ma小)怎么办? 其实这种情况下,我们因为枚举了

所有的最大值,所以在 之前的枚举中 肯定会有一次 枚举到 了这个区间的最大值的。

总结

挺好的一个思路吧, 枚举矛盾点(最大值)是多少, 因为这个关键的地方被确定了,使得问题被简化(或者说分解成很多个简单的步骤)

题解

#include<bits/stdc++.h>
#define ll long long
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%I64d",&x)
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
using namespace std;

const int N = 1e5;

int n;
int a[N+10];

int main(){
    #ifdef LOCAL_DEFINE
        freopen("D:\rush.txt","r",stdin);
    #endif
    ios::sync_with_stdio(0),cin.tie(0);
    cin >> n;
    rep1(i,1,n){
        cin >> a[i];
    }
    int ans = 0;
    rep1(i,1,30){
        int cur = 0;
        rep1(j,1,n){
            if (a[j]>i){
                cur = 0;
            }else{
                cur = cur + a[j];
                ans = max(ans,cur-i);
                if (cur<0) cur = 0;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/13053330.html