uva 12393 Nonnegative 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 }
原文地址:https://www.cnblogs.com/celia01/p/2645747.html