POJ 3368.Frequent values
2015-06-10
问题简述:
输入一个非递减的数组,输出其中下标 i 到 j 中最大连续元素的个数。
原题链接:http://poj.org/problem?id=3368
解题思路:
由于数组长度和查询次数过大,使用遍历算法暴力求解必然导致 TLE,所以我们要另想方法。这里可以使用 RMQ问题中的ST算法或线段树 来优化问题解决的时间复杂度。
方法一:ST算法,即 Sparse Table 算法。它的时间复杂度为<O(nlogn), O(1)>,即预处理为 O(nlogn),而查询仅需O(1)的时间。
本文提供有关该算法的讲稿,链接: http://pan.baidu.com/s/1hqCg17I 密码: d3m3。
方法二:线段树。线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。本题使用线段树存储区间最大值,使得查询时间复杂度降为 O(logn)。
具体操作:使用一个数组 cnt 记录每一个数依次出现的次数,然后使用上述两个算法对这个数组进行操作,使利于查询。为了便于查找原数组下标,还要建立一个数据结构保存 cnt 对应的数的最小下标和最大下标以及 cnt 的下标。
源代码:
ST算法:
1 /* 2 OJ: POJ 3 ID: 3013216109 4 TASK: 3368.Frequent values 5 LANG: C++ 6 NOTE: RMQ(ST算法) 7 */ 8 #include <cstdio> 9 #include <algorithm> 10 #include <cstring> 11 #include <cmath> 12 using namespace std; 13 14 const int MAX=100005; 15 int a[MAX],dp[MAX][18]; 16 int cnt[MAX]; 17 18 struct trip { 19 int s,e; 20 int num; 21 }wap[MAX]; 22 23 int main() 24 { 25 int n,q,x,y,i,j; 26 while(scanf("%d",&n),n) { 27 scanf("%d",&q); 28 memset(wap,0,sizeof(wap)); 29 memset(cnt,0,sizeof(cnt)); 30 int k=1; 31 scanf("%d",&a[1]); 32 wap[k].s=1; 33 for(i=2;i<=n;i++) { 34 scanf("%d",&a[i]); 35 if(a[i]==a[i-1]) { 36 cnt[k]++; 37 //wap[k].e=i; 38 wap[i].s=wap[i-1].s; 39 } 40 else { 41 cnt[k]++; 42 wap[i].e=i-1; 43 k++; 44 wap[i].s=i; 45 } 46 } 47 wap[n+1].e=n; 48 cnt[k]++; 49 for(i=1,j=1;i<=n;) { 50 for(int f=i;f<i+cnt[j];f++) 51 wap[f].num=j; 52 for(int f=i+1;f<i+cnt[j];f++) 53 wap[f].s=wap[f-1].s; 54 for(int f=i+cnt[j]-1;f>=i;f--) 55 wap[f].e=wap[f+1].e; 56 i+=cnt[j];j++; 57 } 58 59 int f; 60 for(f=17;f>=0;f--) 61 if((1<<f)<=k) 62 break; 63 f++; 64 int p=floor(log((double)(n+1))/log(2.0)); 65 for(i=1;i<=k;i++) 66 dp[i][0]=cnt[i]; 67 for(j=1;j<=p;j++) 68 for(i=1;i+(1<<j)-1<=k;i++) 69 dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); 70 71 while(q--) { 72 scanf("%d %d",&x,&y); 73 int i,st,rt,ans; 74 st=wap[x].num; 75 rt=wap[y].num; 76 if((rt-st)==0) 77 ans=y-x+1; 78 else if((rt-st)==1) 79 ans=max(wap[x].e-x+1,y-wap[y].s+1); 80 else { 81 int p=floor((log((double)(rt-st-1))/log(2.0))); 82 ans=max(dp[st+1][p],dp[rt-(1<<p)][p]); 83 ans=max(wap[x].e-x+1,ans); 84 ans=max(ans,y-wap[y].s+1); 85 } 86 printf("%d\n",ans); 87 } 88 } 89 return 0; 90 }
线段树:
1 /* 2 OJ: POJ 3 ID: 3013216109 4 TASK: 3368.Frequent values 5 LANG: C++ 6 NOTE: 线段树 7 */ 8 #include <cstdio> 9 #include <algorithm> 10 #include <cstring> 11 #include <cmath> 12 using namespace std; 13 14 const int MAX=100005; 15 int a[MAX],dp[MAX][18]; 16 int cnt[MAX],tree[MAX*4],f; 17 18 struct trip { 19 int s,e; 20 int num; 21 }wap[MAX]; 22 23 void build(int l,int r,int flag) { 24 if(l==r) { 25 tree[flag]=cnt[f++]; 26 return; 27 } 28 int m=(l+r)/2; 29 build(l,m,flag*2); 30 build(m+1,r,flag*2+1); 31 tree[flag]=max(tree[flag<<1],tree[flag<<1|1]); 32 } 33 34 int query(int x,int y,int l,int r,int flag) { 35 if(x<=l&&r<=y) 36 return tree[flag]; 37 int m=(l+r)/2; 38 int ans=0; 39 if(x<=m) 40 ans=max(ans,query(x,y,l,m,flag<<1)); 41 if(y>m) 42 ans=max(ans,query(x,y,m+1,r,flag<<1|1)); 43 return ans; 44 } 45 46 int main() 47 { 48 int n,q,x,y,i,j; 49 while(scanf("%d",&n),n) { 50 scanf("%d",&q); 51 memset(wap,0,sizeof(wap)); 52 memset(cnt,0,sizeof(cnt)); 53 int k=1; 54 scanf("%d",&a[1]); 55 wap[k].s=1; 56 for(i=2;i<=n;i++) { 57 scanf("%d",&a[i]); 58 if(a[i]==a[i-1]) { 59 cnt[k]++; 60 wap[i].s=wap[i-1].s; 61 } 62 else { 63 cnt[k]++; 64 wap[i].e=i-1; 65 k++; 66 wap[i].s=i; 67 } 68 } 69 wap[n+1].e=n; 70 cnt[k]++; 71 for(i=1,j=1;i<=n;) { 72 for(int f=i;f<i+cnt[j];f++) 73 wap[f].num=j; 74 for(int f=i+1;f<i+cnt[j];f++) 75 wap[f].s=wap[f-1].s; 76 for(int f=i+cnt[j]-1;f>=i;f--) 77 wap[f].e=wap[f+1].e; 78 i+=cnt[j];j++; 79 } 80 f=1; 81 build(1,k,1); 82 while(q--) { 83 scanf("%d %d",&x,&y); 84 int i,st,rt,ans; 85 st=wap[x].num; 86 rt=wap[y].num; 87 if((rt-st)==0) 88 ans=y-x+1; 89 else if((rt-st)==1) 90 ans=max(wap[x].e-x+1,y-wap[y].s+1); 91 else { 92 ans=query(st+1,rt-1,1,k,1); 93 ans=max(wap[x].e-x+1,ans); 94 ans=max(ans,y-wap[y].s+1); 95 } 96 printf("%d\n",ans); 97 } 98 } 99 return 0; 100 }