题目大意:求长度为n的循环数组中,长度为n不重复连续大于0的数字和的个数。。
循环队列:将数组复制一遍开为2*n;
单调队列:此处记录递增序列,q[i] 记录下标;入队操作,从后往前扫,删除比当前元素大的元素,添加当前元素;出队操作,删除该元素位置 - 队首元素位置 > n - 1的元素(即不同框的元素)
用a[i](从1开始)记录i的前缀和
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define N 2000005
using namespace std;
int n;
int a[N], q[N];
int head, rear;
void enqueue(int i)
{
while (head <= rear && a[i] <= a[ q[rear] ]) //删除队尾大于当前元素的元素
{
rear--;
}
q[++rear] = i; //入队
}
void dequeue(int i)
{
if (q[head] < i - n + 1) //不同框的元素删除
{
head++;
}
}
int main()
{
while (~scanf("%d", &n) && n)
{
head = 0, rear = -1; //队首队尾指针
int ans = 0;
for (int i = 1; i <= n; i++) //数组复制
{
scanf("%d", &a[i]);
a[i + n] = a[i];
}
for (int i = 2; i < 2 * n; i++)
{
a[i] += a[i - 1];
}
for (int i = 1; i < n; i++) //将前n - 1个进行入队操作,如数列为-10 3 -1 5 4,
{ //a[i]: -10 -7 -8 -3 1 -9 -6 -7 -2 2 q[i]: 1 3 4
enqueue(i);
}
for (int i = n; i < 2 * n; i++)
{
enqueue(i);
dequeue(i); //如果不在长度为n的框里,出队
if (a[ q[head] ] - a[i - n] >= 0) //长度为n的框里最小前缀和 - 框前一位的前缀和
{
ans++;
}
}
printf("%d\n", ans);
}
return 0;
}