HDU 4193单调队列

题意:

给你一个n项的序列,每次可以把序列的首项移动到末尾,显然一共可以构成n种序列,问一共有多少种序列满足条件:序列的前i项和都大于等于0(i:1~n)。

解题思路:

开一个2*n的数组,后面n项复制前面n项。这样,每个长度为n的区间都代表一种序列。(这也是循环序列的一般做法吧),然后,数组中的值sum[i]记录前面i项的和(1~i)。

这样,我们在考虑以k为起点的区间时,只要把sum[i]-sum[k-1]便可得到以k为起点的序列的前j项和(j=i-k+1)。

如果当前区间中的最小的sum[i]都满足sum[i]-sum[k-1]>=0,那么区间中的所有值也一定满足此条件。

问题从而转化成了如何求滚动区间中的最小值,我们不难想到单调队列的做法。

 


 

/******************************
* author :crazy_石头
* data structure: 单调队列
* created time:2013/10/31 22:18
* Pro:HDOJ 4193
* Judge Status:Accepted
* Memory:19828K
* Time:1078MS
* PS:可以优化输入输出加速,ORZ
*******************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

#define rep(i,h,m) for(int i=(h);i<=(m);i++)

const int maxn=1000000+5;
int sum[maxn<<1],q[maxn<<1],a[maxn<<1];//q存储下标,元素的值可以通过访问下标间接访问到;
int res;
int head,tail,n;

inline void Enqueue(int cur)//维护递增队列;
{
    while(head<=tail&&sum[q[tail]]>sum[cur])
        tail--;
    q[++tail]=cur;
}

inline void Dequeue(int cur)
{
    if(cur>n&&sum[q[head]]-sum[cur-n]>=0)//若最小值减去前面的sum仍旧是非负的,则开始计数;
        ++res;//cur>n和后面的条件不能互换,否则会变为负数越界;
    while(head<=tail&&cur-q[head]>=n-1)
        head++;
}

int main()
{
    while(scanf("%d",&n)!=EOF&&n)
    {
        head=1,tail=0;
        res=0;
        memset(sum,0,sizeof(sum));
        rep(i,1,n)
        {
            scanf("%d",&a[i]);
            a[i+n]=a[i];//往原环状序列后面复制一次该序列来处理循环序列;
        }
        rep(i,1,n<<1)
        {
            sum[i]=sum[i-1]+a[i];//维护前缀和;
        }
        rep(i,1,n<<1)
        {
            Enqueue(i);
            Dequeue(i);
        }
        printf("%d\n",res);
    }
}

* This source code was highlighted byYcdoiT. ( style: Pastie )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值