单调队列-hdu-4193-Non-negative Partial Sums

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4193

题目大意:

给n个数,a0,a1,...an,求ai,ai+1,...an,a1,a2,...ai-1这样的排列种数,使得所有的前k(1<=k<=n)个的和都大于等于0;

解题思路:

求前缀和,加倍序列。

要满足前k个和都>=0,只需最小值>=0,所以用单调队列维护一个最小的前缀和sum[i],(i>=j-n+1),这样就保证了sum[j]-sum[i]最大,所以区间【j-n+1,i]最小。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#define eps 1e-6
#define INF 0x3fffffff
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 1100000
int sum[Maxn<<1];
int q[Maxn];

int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   int n;

   while(scanf("%d",&n)&&n)
   {
       sum[0]=0;
       for(int i=1;i<=n;i++) //求前缀和,并加倍序列
       {
           scanf("%d",&sum[i]);
           sum[i+n]=sum[i];
           sum[i]+=sum[i-1];
       }
       for(int i=n+1;i<2*n;i++)
           sum[i]+=sum[i-1];
       int head=0,tail=-1,ans=0; //开始队列为空
       //q[0]=0;
       for(int i=1;i<2*n;i++)
       {
           while(head<=tail&&sum[i]<=sum[q[tail]])
                tail--;
            q[++tail]=i;//以i结尾
            while(q[head]<i-n+1)
                head++;
            if(i>=n) //看是否存在
            {
                int t=sum[i]-sum[q[head]]; //后面的最大
                if(sum[i]-sum[i-n]-t>=0) //前面一块就最小,最小的大于等于0时,
                    ans++;               //肯定满足题目要求
            }
       }
       printf("%d
",ans);
   }

   return 0;
}


原文地址:https://www.cnblogs.com/pangblog/p/3331316.html