【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
",ans);
	scanf("%d",&n);
  }
  
  return 0;
}


原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793949.html