首页 > 代码库 > FZU 1914 单调队列

FZU 1914 单调队列

 

题目链接:http://acm.fzu.edu.cn/problem.php?pid=1914

题意:

给出一个数列,如果它的前i(1<=i<=n)项和都是正的,那么这个数列是正的,问这个数列的这n种变换里,

A(0): a1,a2,…,an-1,an

A(1): a2,a3,…,an,a1

A(n-2): an-1,an,…,an-3,an-2

A(n-1): an,a1,…,an-2,an-1

问有多少个变换里,所以前缀和都是正整数。

思路:因为变换是a[n]后面接着a[1]所以我们把数组a接到后面(即a[n+1]=a[1]..a[n+n]=a[n])。然后求一个前缀和。然后对于求以a[i]为起点的变换。即a[i],a[i+1],a[i+2]...a[n]...a[i-1]。当该变换满足全部前缀和都为正时,即a[i],a[i]+a[i+1],...,a[i]+...a[i+n]都为正。但是如果对于每个变换都用O(n)时间去计算每一个前缀和会TLE,所以预处理出原始数列的前缀和。那么上面的前缀和就可以转换成sum[i]-sum[i-1], sum[i+1]-sum[i-1],..,sum[i+n]-sum[i-1]。然后对于题目求的所有前缀和都为正,即在所有前缀和的最小值为正即可。那么就可以用滑动窗口维护最小值。用单调队列实现。 注意STL的deque会TLE,所以自己手写了的双端队列。

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>  
#include<string.h>  
#include<cstring>
#include<algorithm>  
#include<queue>  
#include<math.h>  
#include<time.h>
#include<vector>
#include<iostream>
#include<string>
using namespace std;
typedef long long int LL;
const int MAXN = 1e6 + 10;
LL sum[MAXN];
struct Deque{
    int head, tail;
    int val[MAXN];
    Deque(){ head = 0; tail = -1; }
    void push_back(int x){ val[++tail] = x; }
    void pop_back(){ tail--; }
    void pop_front(){ head++; }
    int front(){ return val[head]; }
    int back(){ return val[tail]; }
    bool empty(){ return tail < head; }
    void clear(){ head = 0; tail = -1; }
}deq;
int main(){
//#ifdef kirito
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
//    int start = clock();
    int t, n, Ca = 1; scanf("%d", &t);
    while (t--){
        scanf("%d", &n);
        for (int i = 1; i <= n; i++){
            scanf("%lld", &sum[i]);
            sum[i + n] = sum[i];
        }
        for (int i = 2; i <= 2 * n; i++){
            sum[i] += sum[i - 1];
        }
        int ans = 0; LL tmpx = 0;  deq.clear();
        for (int i = 1; i < n; i++){
            while (!deq.empty() && sum[deq.back()] > sum[i]){
                deq.pop_back();
            }
            deq.push_back(i);
        }
        for (int i = n; i < 2 * n; i++){
            while (!deq.empty() && sum[deq.back()] > sum[i]){
                deq.pop_back();
            }
            deq.push_back(i);
            while (!deq.empty() && deq.front() <= i - n){
                deq.pop_front();
            }
            if (sum[deq.front()] - sum[i - n] > 0){
                ans++;
            }
        }
        printf("Case %d: %d\n", Ca++, ans);
    }
//#ifdef LOCAL_TIME
//    cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
    return 0;
}

 

FZU 1914 单调队列