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;
}
posted @ 2025-10-17 16:28  xuchuhan  阅读(8)  评论(0)    收藏  举报