洛谷1714
解释一下单调队列的原理(一维前缀和请自行百度)
对于这道题来讲,枚举每一个点的前缀和,然后寻找前m个点的前缀和最小值即可。
然后我们发现其实不用O(n)的扫描的,因为假设我们正在处理第i个点,除了第i-1个点没有被比较过以外
前i-1到i-m个点都被比较过了就可以利用这个原理减少重复计算。
然后单调队列,就是让一个队列,有这样的性质,队头最大(或最小),队列里的元素是不严格递减的(或不严格递增)。
在插入时就需要维护这个性质,插入时检查队尾是否比它大,大就pop掉。
这样的话每次检查队头是否有效(无效就pop),然后插入第i-1个·前缀和即可
上代码~
#include<stdio.h>
//by SHADOWICEMCMLXXXIV
using namespace std;
struct data
{
int num;int v;
}q[500010];//手写队列
int sum[500010];
int n;int m;
int head=1;int tail=0;//初始化队列为空
void pop()//手写pop
{
if(head<tail)head++;
return;
}
void push(data x)//push
{
tail++;
q[tail]=x;
return;
}
void pot()//pop队尾
{
if(tail>=head)
{
tail--;
}
return;
}
int res;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&sum[i]);
sum[i]=sum[i]+sum[i-1];//前缀和
}
for(int i=1;i<=n;i++)
{
if(q[head].num<i-m)pop();//如果队头过期就pop掉
while(1)
{
if(sum[i-1]>=q[tail].v||head>tail)//如果是空队列或者是队尾比拆入的小就push
{
data p;p.num=i-1;p.v=sum[i-1];
push(p);break;
}
else
{
pot();//pop队尾
}
}
if(res<sum[i]-q[head].v)res=sum[i]-q[head].v;//处理最大值
}
printf("%d",res);
return 0;//拜拜程序
}
posted on 2017-10-15 17:04 SHADOWICENCXIX 阅读(117) 评论(0) 编辑 收藏 举报