hdu 4193 Non-negative Partial Sums (数据结构_单调队列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4193


题目大意:给定一个由n个整数组成的整数序列,可以滚动,滚动的意思就是前面k个数放到序列末尾去。问有几种滚动方法使得前面任意个数的和>=0.


解题思路:刚拿到题目有暴力求解的冲动,但看到n的范围是1-100万,瞬间就腌了,但隐约觉得这样的题目会有一些性质,这个性质找出来这题目就容易解决。这种滚动序列的题目,一般是复制一份序列到末尾,这题我也这么做了。然后找啊找啊找,发现问题可以转换成判断长度为n的序列中,前面若干个数的和的最小值是否大等于0,如果是大等于0,那它符合条件。

       那现在就好办了,用个单调队列维护一个单调区间,使得区间内的数(其实是前面数的和)递增,然后判断和区间首的差值是否大等于0即可。具体实现见代码,有注释。


测试数据:

3

2 2 1


3

-1 1 1


1

-1


4
-1 1 -1 1


代码:

#include <stdio.h>
#include <string.h>
#define MAX 1000010


struct node{
	
	int sum,in;
}deq[MAX*2];
int ans,head,tail;
int n,arr[MAX],sum[MAX*2];


int main()
{
	int i,j,k;
	
	
	while (scanf("%d",&n),n) {
		
		
		memset(sum,0,sizeof(sum));
		for (i = 1; i <= n; ++i)
			scanf("%d",&arr[i]);
		for (i = 1; i <= n; ++i)
			sum[i] = sum[i-1] + arr[i];
		for (i = n + 1; i <= 2 * n; ++i)
			sum[i] = sum[i-1] + arr[i-n];
		
		
		ans = 0,head = 1,tail = 0;
		for (i = 1; i <= 2 * n; ++i) {
			
			while (head <= tail && sum[i] <= deq[tail].sum)	//让队列保持单调递增
				tail--;										//当前元素如果比之前的小,则肯定比之前的更优
			deq[++tail].sum = sum[i];						//插入都队尾
			deq[tail].in = i;								//记录下标
			if (i > n && deq[head].sum - sum[i-n] >= 0)		//如果队列区间中最小的和大于0,则肯定符合条件
				ans++;
			while (head <= tail && i - deq[head].in >= n - 1)//去掉不和谐的元素,也在移动区间
				head++;
		}
		
		
		printf("%d\n",ans);
	}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

你可能感兴趣的:(数据结构,struct,测试)