codeforces1197D Yet Another Subarray Problem dp

网址:http://codeforces.com/problemset/problem/1197/D

题意:

给出长度为$n$的序列和$m$,$k$($n \leq 3e5,m \leq 10,k \leq 1e9$),求$\sum_{i=l}^{r}a_i-k \lceil \frac {r-l+1}{m} \rceil$的最大值。

题解:

第一眼下去感觉是最大子列和,然后直接WA at t3和t8。感觉没问题,后面想想其实不行,因为减去的区间长度是随着子列的长度变化的,就算记录了选取的区间长度进行在线处理。没有丢掉的一段在减去对应的值之后也可能小于丢掉的。所以这个题只能对每一个数枚举其位置,即$j%m==i?(i \in [0,m-1])$,然后让右端点处(满足$j%m==i$)的值减去一个$k$,构成新序列,在新序列上求最大子列和。求解时一定要在到达右端点时才更新最大值,否则会漏减一个$k$。为什么需要这么做?答案一定是出现在某次枚举的右端点,这样子枚举可以在不需要分类讨论就减去相应个数的k,否则有可能出现区间长度大于一个$m$的区间只减去了一个$k$的错误结果。

AC代码:

#include <bits/stdc++.h>
using namespace std;
long long a[300005],b[300005];
int main()
{
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=0;i<n;++i)
        cin>>a[i];
    long long maxx=0,ans=0;
    for(int i=0;i<m;++i)//枚举减k的位置
    {
        for(int j=0;j<n;++j)
            b[j]=a[j]-(j%m==i?k:0);//对需要减k的地方处理
        maxx=0;
        for(int j=0;j<n;++j)
        {
            maxx=max(maxx+b[j],0ll);//求最大子列和
            if(j%m==i)
                ans=max(ans,maxx);//保证了所有的最大子列和都减了相应个数的k
            cout<<maxx<<" ";
        }
        cout<<endl;
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Aya-Uchida/p/11298594.html