题目描述
今天是小Z的生日,同学们为他带来了一块蛋糕。这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每小块都有对应的幸运值。
小Z作为寿星,自然希望吃到的第一块蛋糕的幸运值总和最大,但小Z最多又只能吃M小块(M≤N)的蛋糕。
吃东西自然就不想思考了,于是小Z把这个任务扔给了学OI的你,请你帮他从这N小块中找出连续的k块蛋糕(k≤M),使得其上的幸运值最大。
输入输出格式
输入格式
输入文件cake.in的第一行是两个整数N,M。分别代表共有N小块蛋糕,小Z最多只能吃M小块。
第二行用空格隔开的N个整数,第i个整数Pi代表第i小块蛋糕的幸运值。
输出格式
输出文件cake.out只有一行,一个整数,为小Z能够得到的最大幸运值。
输入输出样例
输入样例
样例输入1
5 2
1 2 3 4 5样例输入2
6 3
1 -2 3 -4 5 -6
输出样例
样例输出1
9样例输出2
5
题解
一道求最大不定长区间和的问题
区间[i,j]和的最大值ans(i,j)=max{sum[j]-sum[i-1],j-m<i<=j}(其中sum[j]是前缀和数组),我们可以选择去枚举右端点,那么sum[j]就是定值,上面的方程可以化简为ans(i,j)=sum[j]-min{sum[i-1],j-m<i<=j},这样只需要用单调队列维护区间内最小的sum[i-1]就好了
代码
#include<cstdio>
#include<cstring>
const int MAXN=500050;
struct T
{
int v,pos;
}q[MAXN];
int sum[MAXN],a[MAXN],m,n,ans;
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline int maxx(int x,int y){return x>y?x:y;}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;++i)
{
a[i]=read();
sum[i]=sum[i-1]+a[i];
}
int head=0,tail=1;
q[tail].v=sum[1];
q[tail].pos=1;
ans=sum[1];
for(int i=2;i<=n;++i)
{
while(head!=tail&&q[tail].v>sum[i])
--tail;
q[++tail].v=sum[i];
q[tail].pos=i;
while(head!=tail&&q[head+1].pos<i-m)
++head;
ans=maxx(sum[i]-q[head+1].v,ans);
}
printf("%d\n",ans);
return 0;
}