题解 - CF1197D Yet Another Subarray Problem
其他
2020-06-26 11:18:06
阅读次数: 0
CF1197D Yet Another Subarray Problem 题解
题目意思
- 就是给你一个序列
a,以及
m,k,定义区间
[l,r]的权值为
∑ai−k×⌈mr−l+1⌉
- 求那个区间权值最值
-
n≤3×105,m≤10,k≤109
Sol
- 一看
m就知道和
m有关。这道题目有两种方法我都仔细讲一下。
Sol1
- 考虑
DP,设
fi,j表示到
i连续取得个数
s%m=j的最大值
- 考虑转移
- 若
j=0显然是从上一段转移过来,所以转移显然
fi,j=max(0,fi−1,m−1)
- 若
j=1显然就是重开一段,那么转移就是
fi,j=fi−1,0−k+ai,因为重开一段要减去
m(后面就不用减了)再加上自己的权值
ai
- 其余情况:
fi,j=max(fi−1,j−1+ai)
- 答案就是
maxfi,j
- 但是这种方法要特判
m=1的情况(这个就很简单了)
- 复杂度
O(n×m)
Code1
#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=3e5+5;
int n,m,s,ans=-1e12,a[N],f[N][11];
signed main()
{
n=read();
m=read();
s=read();
for ( int i=1;i<=n;i++ ) a[i]=read();
if(m==1)
{
int tot=0;
for ( int i=1;i<=n;i++ )
{
tot+=a[i]-s;
ans=max(ans,tot);
tot=max(tot,0ll);
}
printf("%lld\n",max(0ll,ans));
return 0;
}
memset(f,128,sizeof f);
for ( int i=0;i<=n;i++ ) f[i][0]=0;
for ( int i=1;i<=n;i++ )
for ( int j=0;j<=min(i,m-1);j++ )
{
if(j==1)
f[i][j]=f[i-1][0]+a[i]-s;
else if(!j) f[i][j]=max(0ll,f[i-1][m-1]+a[i]);
else
f[i][j]=max(f[i][j],f[i-1][j-1]+a[i]);
ans=max(ans,f[i][j]);
}
printf("%lld\n",ans);
return 0;
}
Sol2
- 我们还是考虑和
m有关
- 我们枚举从哪个数(假设
p)开始,那么对于后面的数
ai,ai+m×k都要减去
s,那么
sumi=∑ai−s((i−p)%m=0)
- 然后对于每个
p+m×k去更新答案,我们设
sufi=maxi=lnsumi
- 那么最大值就是
sufi−sumi−1
- 复杂度
O(n×m)
- 代码没写过,就不放了(主流算法还是这个)
转载自blog.csdn.net/wangyiyang2/article/details/105271109