CF1197D 题解
发现 \(m\leq 10\),考虑从这方面入手。
刚开始的想法是设计一些基础算法拼在一起,或是观察一些性质,配合 \(m\leq 10\) 去设计程序,但是没搞出来。/bangbangt
后面看了题解,发现容易设计一个简介的 DP。\(dp_{i,j}\) 表示前 \(i\) 个,钦定 \(i\) 必选,选择长度\(\bmod m=j\),最优贡献。转移是容易的:\(j=1\) 则 \(dp_{i,j}=dp_{i-1,j-1}-k+a_i\);否则 \(dp_{i,j}=dp_{i-1,j-1}+a_i\)。
但是需要特殊处理一下 \(m=1\) 的情况,即处理出最大的 \(\sum_{i=l}^r a_i-k(r-l+1)\)。把式子拆开,则有 \(s_r-s_{l-1}-kr+k(l-1)=(s_r-kr)-(s_{l-1}-k(l-1))\)。这个东西的最大值是容易 \(\mathcal{O(n)}\) 维护的。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5,inf=0x3f3f3f3f3f3f3f3f;
int n,m,k,ans,a[N],d[N],dp[N][15];
void work(){
for(int i=1;i<=n;i++){
cin>>a[i],a[i]+=a[i-1];
d[i]=a[i]-k*i;
}
int Min=0;
for(int i=1;i<=n;i++)ans=max(ans,d[i]-Min),Min=min(Min,d[i]);
return cout<<ans,void();
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
if(m==1)work(),exit(0);
memset(dp,-0x3f,sizeof(dp));
for(int i=1,x;i<=n;i++){
cin>>x,dp[i][1]=x-k;
for(int j=0;j<m;j++){
if(!j)dp[i][j]=max(dp[i][j],dp[i-1][m-1]+x);
else if(j==1)dp[i][j]=max(dp[i][j],dp[i-1][j-1]-k+x);
else dp[i][j]=max(dp[i][j],dp[i-1][j-1]+x);
ans=max(ans,dp[i][j]);
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号