题意很清晰,就不多讲了。
我们不难想到可以用DP来做:
dp[i]表示以第i块蛋糕为结尾时,所能获得的最大幸运值。
记sum[i]为1~i块蛋糕的幸运值的总和。则
状态转移方程:dp[i]=sum[i]-min(sum[j]), i-m<=j<=i。
当j==i的时候,表示一块蛋糕也不吃,这种情况是允许的。
于是,我们只要在[i-m,i]之中找到最小sum值,就可以完成状态转移。朴素算法是O(n2),但是我们仔细观察一下就会发现这道题也有滑动窗口的性质,所以我们可以用单调递增队列,维护[i-m,i]内最小的sum值。这样可以将O(n2)优化为O(n)。
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=5e5+5;
int a[maxn],dp[maxn];
int sum[maxn];
deque<int> Q;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
sum[0]=0;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
Q.push_back(0);
for(int i=1;i<=n;++i)
{
if(Q.empty()) Q.push_back(i);
else
{
while(!Q.empty()&&Q.front()<i-m)
Q.pop_front();
while(!Q.empty()&&sum[Q.back()]>sum[i])
Q.pop_back();
Q.push_back(i);
}dp[i]=sum[i]-sum[Q[0]];
}
int ans=-inf;
for(int i=1;i<=n;++i) ans=max(ans,dp[i]);
printf("%d\n",ans);
return 0;
}