UVALive_5825

UVALive_5825

    一个可行的思路就是扫描一遍,求出以i为左端点的且长度不超过N的区间和的最小值,如果这个最小值都大于或等于0的话,那么显然以i为左端点就是可行的。

    既然是区间求和,那么一般来说用前缀和比较方便,这样实际上对于每个i我们就是去找满足j>i&&j<=i+N的最小的A[j],其中A[]表示前缀和。

    我是用后缀和做的,如果用后缀和的话结论类似。

#include<stdio.h>
#include<string.h>
#define MAXD 2000010
#define INF 0x7fffffff
int N, M, A[MAXD], a[MAXD], q[MAXD];
void init()
{
int i, j, k;
for(i = 1; i <= N; i ++)
scanf("%d", &a[i]);
for(i = N + 1; i <= (N << 1); i ++)
a[i] = a[i - N];
A[2 * N + 1] = 0;
for(i = 2 * N; i > 0; i --)
A[i] = A[i + 1] + a[i];
}
void solve()
{
int i, j, k, front, rear, ans;
front = rear = ans = 0;
for(i = 2; i <= N; i ++)
{
while(front < rear && A[i] > A[q[rear - 1]])
-- rear;
q[rear ++] = i;
}
for(i = 1; i <= N; i ++)
{
k = i + N;
while(front < rear && q[front] <= i)
++ front;
while(front < rear && A[k] > A[q[rear - 1]])
-- rear;
q[rear ++] = k;
if((long long int)A[i] - A[q[front]] >= 0)
++ ans;
}
printf("%d\n", ans);
}
int main()
{
for(;;)
{
scanf("%d", &N);
if(!N)
break;
init();
solve();
}
return 0;
}

 

原文地址:https://www.cnblogs.com/staginner/p/2402884.html