uva 12393 Non-negative Partial Sums 【单调队列】

后来看了07年周泽(大概是?)的论文,才知道原来这个是一个很经典的单调队列题。

题意:给出一个长度为n序列,每次将第一个元素移至最后可以得到有n种序列,问其中有多少个满足对于所以的i(1≤i≤n),sigma(a[k]),(1≤k≤i)>=0,就是可以维护一个递增的序列,这样每次取队首就O(1)的求出是否满足条件了,维护序列只需要O(n)的复杂度。

比赛的时候用dp思想的st(rmq)的O(nlogn)的算法超时了,后来知道原来有一种RMQ转换为LCA,又转化为RMQ的算法可以做,这样复杂度也可要跟单调队列的做法一样,转换为O(n)。

这类单调队列的基本做法吧。

比较习惯的写法:

l=0; r=-1;

for(k=0;k<=n;k++){

  while(l<=r&&(没有更优的判断条件,直接带入r计算即可)) r--;

  q[++r] = k;

  /*if(判断是否有符合题目的解) ans++;(类似的)

  while(对于l的边界条件,下一次的l不符合判断条件) l++;*/

  或者

  while(对于l的边界条件,此次l不符合判断条件) l++;

  if(判断是否有符合题目的解) ans++;(类似的)

  

}

 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cmath>

 4 #include<algorithm>

 5 #include<cstring>

 6 #include<map>

 7 #define see(x) cout<<#x<<":"<<x<<endl;

 8 using namespace std;

 9 const int maxn = 1000005;

10 int a[maxn], sum[maxn<<1], que[maxn<<1];

11 int main(){

12     int n, i, j, k, s, ans, l, r;

13     while(~scanf("%d",&n)&&n){

14         scanf("%d",&a[0]);

15         sum[0] = a[0];

16         for(i=1;i<n;i++){

17             scanf("%d",&a[i]);

18             sum[i] = sum[i-1]+a[i];

19         }

20         for(i=n;i<2*n;i++){

21             sum[i] = sum[i-1]+a[i-n];

22         }

23         ans = 0;

24         l = r = 0;

25         for(i=0;i<2*n;i++){

26             while(l<r&&sum[i]<sum[que[r-1]]) r--;

27             que[r++] = i;

28             if(i>=n&&sum[que[l]]-sum[i-n]>=0) ans++;

29             while(l<r&&que[l]<=i-n+1) l++;

30         }

31         printf("%d\n",ans);

32     }

33     return 0;

34 }

 

你可能感兴趣的:(part)