切蛋糕

题目描述

今天是小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;
}
posted @ 2017-04-16 23:03  dustbin  阅读(296)  评论(0)    收藏  举报