【转载自】http://blog.ac521.org/?p=123
【题目描述】
给定一个长n的循环队列(n<=1000000),可以循环形成序列(共n种),对于每种序列求前i项和sum(i),求形成的循环序列有多少种 满足任意的sum(i)>=0;
【解题思路】
【题目描述】
给定一个长n的循环队列(n<=1000000),可以循环形成序列(共n种),对于每种序列求前i项和sum(i),求形成的循环序列有多少种 满足任意的sum(i)>=0;
【解题思路】
首先用循环序列的一般处理方法,两个接在一起,然后处理出来sum,使用单调队列,滚动求长n的子序列的最小值。如果最小值减去前面的sum仍然是非负的,则计数。
#define N 1000002
int num[N * 2];
int q[N * 2], p[N * 2];
char s[N * 3];
int head, rear;
int main()
{
int n, m, i, j;
while (scanf("%d", &n) == 1 && n != 0) {
int end = n * 2;
getchar();
gets(s);
int index = 0, l = strlen(s);
int number = 0;
int tag = 0;
for (i = 0; i < l; ++i) {
if (s[i] == '-') {
tag = 1;
continue;
}
if (isdigit(s[i])) {
number = number * 10 + s[i] - '0';
} else {
if (tag == 1) number *= -1;
num[index++] = number;
num[index + n - 1] = number;
tag = 0;
number = 0;
}
}
if (index < n) {
if (tag == 1) number *= -1;
num[index++] = number;
num[index + n - 1] = number;
}
for (i = 1; i < end; ++i)
num[i] += num[i - 1];
head = 0, rear = -1;
m = 0;
for (i = 0; i < end; ++i) {
while (head <= rear && num[i] <= q[rear])
rear--;
q[++rear] = num[i];
p[rear] = i;
if (i >= n) {
while (head <= rear && p[head] < i - n + 1)
head++;
int sum = num[i - n];
if (q[head] - sum >= 0)
++m;
}
}
printf("%d\n", m);
}
return 0;
}