SHADOWICENCXIX

导航

洛谷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编辑  收藏  举报