Codeforces 1197D Yet Another Subarray Problem

题目链接:

题意:给一个长为n(3e5)的数组,我们可以任意选择区间[l,r],该区间的值为sum(l~r)-k*上界((r-l+1)/m),求最大的值为多少

分析:这道题如果没有后面的需要减的,就是一个标准的最大子段和了,可以用dp的方法O(1)解决:

用dp[i]表示以i结尾的子区间最大值,有dp[i]=max(a[i],dp[i-1]+a[i])

现在有了后面要减的,情况就变复杂了很多

我写的时候,因为我觉得当前状态会收到前面的情况是第几个的影响(1~m都只需要减一个k,m+1~2m需要减2个k....),不满足dp的无后效性,就把dp做法给否了。

事实上,既然会受到前面情况是第几个的影响,那干脆第二维就说明是第几个,枚举每个情况,这样就满足无后效性了

初始化的时候要注意,一开始没初始化,调试了很久

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=1e18;
const int maxn=3e5+7; 
const int mod=1e9+7;
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
#define ls rt<<1
#define rs rt<<1|1
#define mid (l+r)>>1
ll a[maxn],dp[maxn][20];
ll dp2[maxn];
int main(){
    ll n,m,k;scanf("%I64d%I64d%I64d",&n,&m,&k);
    ll ans=0;
    for(int i=1;i<=n;i++){
        scanf("%I64d",&a[i]);
    }
    if(m==1){
        for(int i=1;i<=n;i++){
            dp2[i]=max(dp2[i],dp2[i-1]+a[i]-k);
            ans=max(ans,dp2[i]);
        }
        printf("%I64d
",ans);
        return 0;
    }
    for(int i=0;i<=n;i++)for(int j=i+1;j<=m;j++)dp[i][j]=-inf;
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<m;j++){
            if(i<j)break;
            if(j==0){
                //此时可能是拿了m个的倍数或者是0个 
                dp[i][j]=max(dp[i-1][m-1]+a[i],(ll)0);
            }
            else if(j==1){
                //重新开始了一段m,所以要减k 
                dp[i][j]=dp[i-1][0]+a[i]-k;
            }
            else dp[i][j]=dp[i-1][j-1]+a[i];
            ans=max(ans,dp[i][j]); 
        }
    }
    printf("%I64d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/qingjiuling/p/11622908.html