POJ 3368 (ST表)
链接:http://poj.org/problem?id=3368
题意:给出n个连续单调不递减数,q次询问,每次询问区间(L,R)出现频率最多的数,问出现了多少次
思路:因为n个数是单调不递减的,所以可以预处理一个频率数组cnt[ ],cnt[ i ]记录某个数到 i 位置时,出现了多少次,再预处理一个index数字,记录每一段相同的数字,最右端的位置,因为每次询问的时候可能会出现一部分连续的数被L这个位置隔开,cnt[i]只记录了某个数到i位置出现了多少次,被隔开的部分多算了,所以需要减去,每次询问(L,R)的时候分为两个部分,前一部分查询出 index[ L ] - l为被隔开的部分,后一部分用st表维护区间最值求即可。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 using namespace std; 8 const int maxn = 100005; 9 int n,q; 10 int a[maxn]; 11 int cnt[maxn]; 12 int index[maxn]; 13 int Log[maxn]; 14 int f[maxn][21]; 15 void pre(){ 16 Log[1] = 0; 17 Log[2] = 1; 18 for(int i =3;i<maxn;i++) Log[i] = Log[i/2] + 1; 19 } 20 void st(){ 21 for(int i = 1;i<=n;i++){ 22 f[i][0] = cnt[i]; 23 } 24 for(int j = 1;j<=Log[n+1];j++){ 25 for(int i = 1;i+(1<<j)-1<=n;i++){ 26 f[i][j] = max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 27 } 28 } 29 } 30 int main(){ 31 pre(); 32 while(~scanf("%d",&n)){ 33 if(n == 0) break; 34 scanf("%d",&q); 35 for(int i = 1;i<=n;i++){ 36 scanf("%d",&a[i]); 37 if(i == 1) cnt[i] = 1; 38 if(a[i]!=a[i-1]) cnt[i] = 1; 39 else cnt[i] = cnt[i-1] + 1; 40 } 41 st(); 42 for(int i = n;i>=1;i--){ 43 if(a[i] == a[i+1]) index[i] = index[i+1]; 44 else index[i] = i; 45 } 46 while(q--){ 47 int l,r; 48 int ans = 0; 49 scanf("%d%d",&l,&r); 50 if(index[l] == index[r]){ 51 ans = r - l + 1; 52 } 53 else if(index[l] == index[l-1]){//判断一下,如果在l左边的数和l位置的数相等,就说明被隔开了 54 int t = min(index[l],r)+1;//算出后一部分区间的左端点 55 int ans1 = t - l ;//ans1单独计算 算出被隔开了多少数,这一部分单独计算 56 int s = Log[r-t+1];//剩下部分用st表求 57 ans = max(ans1,max(f[t][s],f[r-(1<<s)+1][s]));//两者取最大值 58 } 59 else{ 60 int s = Log[r-l+1]; 61 ans = max(f[l][s],f[r-(1<<s)+1][s]); 62 } 63 printf("%d\n",ans); 64 } 65 } 66 return 0; 67 }