[POJ] 3368 / [UVA] 11235 - Frequent values [ST算法]

2007/2008 ACM International Collegiate Programming Contest 
University of Ulm Local Contest

 

Problem F: Frequent values

You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.

Input Specification

The input consists of several test cases. Each test case starts with a line containing two integers n and q(1 ≤ n, q ≤ 100000). The next line contains n integers a1 , ... , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1, ..., n}) separated by spaces. You can assume that for each i ∈ {1, ..., n-1}: ai ≤ ai+1. The following q lines contain one query each, consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which indicate the boundary indices for the query.

The last test case is followed by a line containing a single 0.

Output Specification

For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.

Sample Input

10 3

-1 -1 1 1 1 1 3 10 10 10

2 3

1 10

5 10

0

Sample Output

1

4

3

题解:因为序列a1,a2,a3...an是不下降的,所以相同的数字肯定连续集中在一段。维护d[i][0]为相同数字从左到右分别从1到n开始编号,例如样例中的d[i][0]从左到右为 1,2,1,2,3,4,1,1,2,3。这样就转化成了RMQ问题。因为没有中途修改a[i]的值,所以可以用Sparse-Table算法,d[i][j]表示从i开始长度为2^i的一段元素的最大值。维护数组Left[i],Right[i]分别为相同数字连续一段最左端的编号和最右端的编号,例如样例中的Left[i]分别为:1,1,3,3,3,3,7,8,8,8。所以,序列分布共有以下几种情况:

[POJ] 3368 / [UVA] 11235 - Frequent values [ST算法]              
     [1] ans=max(Right[i]-L+1,R-Left[j]+1)
[POJ] 3368 / [UVA] 11235 - Frequent values [ST算法]     [2] ans=R-L+1

[POJ] 3368 / [UVA] 11235 - Frequent values [ST算法]     [3] ans=max(max(Right[i]-L+1,R-Left[j]+1),RMQ(k))

代码:
  1 #include<stdio.h>

  2 #include<string.h>

  3 #include<math.h>

  4 #include<ctype.h>

  5 #include<stdlib.h>

  6 #include<stdbool.h>

  7 

  8 #define rep(i,a,b)      for(i=(a);i<=(b);i++)

  9 #define red(i,a,b)      for(i=(a);i>=(b);i--)

 10 #define clr(x,y)        memset(x,y,sizeof(x))

 11 #define sqr(x)          (x*x)

 12 #define LL              long long

 13 

 14 int i,j,n,m,maxn,q,

 15     a[100003],d[100003][50],Left[100003],Right[100003];

 16 

 17 void pre()

 18 {

 19     clr(d,0);

 20     clr(Left,0);

 21     clr(Right,0);

 22     clr(a,0);

 23 }

 24 

 25 int max(int a,int b)

 26 {

 27     if(a>b) return a;

 28     return b;

 29 }

 30 

 31 int RMQ_init()

 32 {

 33     int i,j;

 34      

 35     for(j=1;(1<<j)<=n;j++)

 36         for(i=1;i+(1<<j)-1<=n;i++)

 37         d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);

 38     

 39     return 0;

 40         

 41 }

 42 

 43 int RMQ(int L,int R)

 44 {

 45     int k;

 46     k=0;

 47     

 48     while(1<<(k+1)<=R-L+1) k++;

 49  

 50     maxn=max(d[L][k],d[R-(1<<k)+1][k]);;

 51    

 52     return 0;

 53     

 54 }

 55 

 56 int Num_init()

 57 {

 58     int i;

 59 

 60     a[0]=35113;

 61     rep(i,1,n)

 62         if(a[i]!=a[i-1]) Left[i]=i;

 63         else Left[i]=Left[i-1];

 64   

 65     a[n+1]=35113;

 66     red(i,n,1)

 67         if(a[i]!=a[i+1]) Right[i]=i;

 68         else Right[i]=Right[i+1];

 69     

 70     

 71     return 0;

 72 }

 73 

 74 int main()

 75 {

 76     int i,x,y;

 77     

 78      while(true) {

 79          pre();    

 80          scanf("%d",&n); 

 81         

 82          if(n==0) exit(0);

 83          scanf("%d",&q);

 84          a[0]=35113;

 85          rep(i,1,n) {

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

 87             if(a[i]!=a[i-1]) d[i][0]=1;

 88             else d[i][0]=d[i-1][0]+1;

 89             

 90          }

 91            

 92         Num_init();  

 93         RMQ_init();

 94 

 95         while(q--) {

 96             scanf("%d%d",&x,&y);

 97             if(Left[x]==Left[y]) printf("%d\n",y-x+1);

 98             else { 

 99                 if(Right[x]+1==Left[y]) printf("%d\n",max(Right[x]-x+1,y-Left[y]+1));

100                 else {       

101                      RMQ(Right[x]+1,Left[y]-1);

102                      printf("%d\n",max(max(Right[x]-x+1,y-Left[y]+1),maxn));

103                 }

104             }

105         }

106     }   

107     

108     

109     return 0;

110 }
 
  

 

 

你可能感兴趣的:(value)