计蒜客之切蛋糕
很难受,当时做的时候看着这题好熟悉,并且想起来是单调队列的做法,可还是没写出来,一直错
题目分析
m 块蛋糕,要求和最大,求出最大和,这个和滑动窗口的类型题一样,把那个 m 长度的连续蛋糕当做窗口,每次窗口左右移动,找出最大值用 ans 记录,最后输出,但是这里需要注意的是 m 是最大子段的长度,所以窗口大小不是固定的,我们用 sum 数组存储前缀和,并不能直接 ans = max(ans,sum[i+m-1]-sum[i-1]);所以用到了单调队列
如果队首的到这个点的距离大于了m就弹出
如果队尾的值大于将要放入的这个前缀和就弹出
最后这个点的值和队首的差就是这个点的最优解
比较找最大值就好了
AC代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 5e5+10;
int a[N]={0};
int s[N]={0},q[N]={0};
int main(){
int n,m;
long long mx=0;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
}
int t=1,h=1,ans=-INF;q[1]=0;
for(int i=1;i<m;i++){
while(h<=t&&s[q[t]]>=s[i])t--;
q[++t]=i;
ans=max(ans,s[i]-s[q[h]]);
}
for(int i=m;i<=n;i++){
while(h<=t&&s[q[t]]>=s[i])t--;
q[++t]=i;
while(h<=t&&q[h]<i-m)h++;
ans=max(ans,s[i]-s[q[h]]);
}
cout<<ans<<endl;
return 0;
}