HDOJ-4193-Non-negative Partial Sums【单调队列】

HDOJ-4193-Non-negative Partial Sums【单调队列】

Problem Description
You are given a sequence of n numbers a0,…, an-1. A cyclic shift by k positions (0<=k<=n-1) results in the following sequence: ak ak+1,…, an-1, a0, a1,…, ak-1. How many of the n cyclic shifts satisfy the condition that the sum of the fi rst i numbers is greater than or equal to zero for all i with 1<=i<=n?

Input
Each test case consists of two lines. The fi rst contains the number n (1<=n<=106), the number of integers in the sequence. The second contains n integers a0,…, an-1 (-1000<=ai<=1000) representing the sequence of numbers. The input will finish with a line containing 0.

Output
For each test case, print one line with the number of cyclic shifts of the given sequence which satisfy the condition stated above.

Sample Input
3
2 2 1
3
-1 1 1
1
-1
0

Sample Output
3
2
0

题目链接:HDOJ-4193

题目大意:给定一个长度为n的循环序列,从n个不同位置开始,问有几个位置使得一下情况成立:所有前缀的和都大等于0(n <=100万).

题目思路:1将序列扩充两倍,算出各项前缀和,记在sum数组里面
2.红色边框为滑动窗口,以i为结尾,每次取n长度的序列,找出这个子序列中最小的sum[]值minnum
3.如果minnum比sum[i - n]大,说明这个子序列中每一项都比sum[i - n]大,即该子序列满足条件
这里写图片描述

注意:找出一个子序列中最小的sum值需要用到单调队列

单调队列:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。

以下是代码:

#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
struct node
{
    int sum,id;
}q[2000010];
int a[2000010];
int sum[2000010];

int main(){
    int n;
    while(scanf("%d",&n) && n)
    {
        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            sum[i] = sum[i - 1] + a[i];
        } 
        for (int i = 1; i <= n; i++) 
        {
            sum[i + n] = sum[i + n - 1] + a[i];
        }
        int front = 0,head = 0,ans = 0;   
        for (int i = 1; i <= 2 * n; i++)
        {
            while(front < head && sum[i] < q[head - 1].sum) head--; //q单调队列记录单调递增的sum[]值及下标
            q[head].sum = sum[i];   
            q[head++].id = i;   
            if (i > n && q[front].sum >= sum[i - n]) ans++;    //满足条件
            while(front < head && q[front].id <= i - n + 1) front++; //如果这个最小sum[]值不在这个序列范围,找下一个最小值

        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(hdoj,4193)