【HDU4193】Non-negative Partial Sums-单调队列
题目大意:有一个包含N个数的数列,可以将前面的K(0≤K≤N-1)个数移到数列的后面,形成N个数列,求在这些数列当中,有多少个数列满足:对于所有的i(1≤i≤N),数列的前i个数之和为非负数。
做法:首先,将该数列复制一份放在该数列的后面,形成一个长度为2*N的数列,用sum[i]表示该数列中前i个数的和。我们发现,对于题目中所说的,将数列前面的K个数移到数列后面所形成的数列,可以得出该数列中前i项的和为:sum[i+K]-sum[K],由于对于每个K来说,sum[K]是固定的,所以我们只需要知道在sum[K+1]到sum[K+n]中的最小值减去sum[K]是不是非负数,就可以判断这个数列符不符合条件了。于是这个问题就转化为求滚动区间的最小值的问题了,不难想到用单调队列维护的做法。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define inf 999999999
using namespace std;
int n;
int sum[2000010];
struct {int val;int pos;} q[1000010];
int main()
{
scanf("%d",&n);
while(n!=0)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&sum[i]);
sum[i+n]=sum[i];
}
for(int i=2;i<=n*2;i++)
sum[i]+=sum[i-1];
int h=0,t=0;
memset(q,0,sizeof(q));
for(int i=1;i<n;i++)
{
while(h<t&&q[h].pos<i-n+1) h++;
while(h<t&&q[t-1].val>=sum[i]) t--;
q[t].val=sum[i];q[t].pos=i;t++;
}
int ans=0;
for(int k=1;k<=n;k++)
{
while(h<t&&q[h].pos<k) h++;
while(h<t&&q[t-1].val>=sum[n+k]) t--;
q[t].val=sum[n+k];q[t].pos=n+k;t++;
if (q[h].val-sum[k-1]>=0) ans++;
}
printf("%d\n",ans);
scanf("%d",&n);
}
return 0;
}