单调队列-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 1100000int 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\n",ans); } return 0;}