题目链接:http://poj.org/problem?id=3294
多个串中,出现次数为k次的最长公共子串的个数,并且输出。
一般的算法就是后缀数组加二分,复杂度O(n*logn)。其实也可以和POJ3415一样维护一个栈,思想都是差不多的,维护一个单调递增的栈,每到一个height[i]时,先保证栈单调递增并且统计个数sum,然后height[i]再与当前最优值比较,如果大于最优值,那么看sum是否大于k,如果大于则更新最优值。平均复杂度O(n)。
二分代码:
1 //STATUS:C++_AC_375MS_4328KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 #include<map> 13 using namespace std; 14 #define LL long long 15 #define pii pair<int,int> 16 #define Max(a,b) ((a)>(b)?(a):(b)) 17 #define Min(a,b) ((a)<(b)?(a):(b)) 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 #define lson l,mid,rt<<1 20 #define rson mid+1,r,rt<<1|1 21 #define PI acos(-1.0) 22 const int N=101010,INF=0x3f3f3f3f,MOD=10000,STA=8000010; 23 const LL LNF=0x3f3f3f3f3f3f3f3f; 24 const double DNF=1e13; 25 // 26 void swap(int& a,int& b){int t=a;a=b;b=t;} 27 void swap(LL& a,LL& b){LL t=a;a=b;b=t;} 28 // 29 30 int num[N]; 31 int sa[N],t1[N],t2[N],c[N],rank[N],height[N],vis[N],ma[N]; 32 int n,m,T; 33 34 void build_sa(int s[],int n,int m) 35 { 36 int i,k,p,*x=t1,*y=t2; 37 //第一轮基数排序 38 for(i=0;i<m;i++)c[i]=0; 39 for(i=0;i<n;i++)c[x[i]=s[i]]++; 40 for(i=1;i<m;i++)c[i]+=c[i-1]; 41 for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; 42 for(k=1;k<=n;k<<=1){ 43 p=0; 44 //直接利用sa数组排序第二关键字 45 for(i=n-k;i<n;i++)y[p++]=i; 46 for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k; 47 //基数排序第一关键字 48 for(i=0;i<m;i++)c[i]=0; 49 for(i=0;i<n;i++)c[x[y[i]]]++; 50 for(i=1;i<m;i++)c[i]+=c[i-1]; 51 for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; 52 //根据sa和x数组计算新的x数组 53 swap(x,y); 54 p=1;x[sa[0]]=0; 55 for(i=1;i<n;i++) 56 x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; 57 if(p>=n)break; //已经排好序,直接退出 58 m=p; //下次基数排序的最大值 59 } 60 } 61 62 void getHeight(int s[],int n) 63 { 64 int i,j,k=0; 65 for(i=0;i<=n;i++)rank[sa[i]]=i; 66 for(i=0;i<n;i++){ 67 if(k)k--; 68 j=sa[rank[i]-1]; 69 while(s[i+k]==s[j+k])k++; 70 height[rank[i]]=k; 71 } 72 } 73 74 int binary(int l,int r) 75 { 76 int i,j,mid,ok,ret,k,cnt; 77 mem(vis,0);k=1; 78 while(l<=r){ 79 mid=(l+r)>>1; 80 cnt=1;ok=0; 81 vis[ma[sa[1]]]=k; 82 for(i=2;i<=n;i++){ 83 if(height[i]>=mid){ 84 if(vis[ma[sa[i]]]!=k)vis[ma[sa[i]]]=k,cnt++; 85 } 86 else { 87 if(cnt>T/2){ok=1;break;} 88 k++;cnt=1; 89 vis[ma[sa[i]]]=k; 90 } 91 } 92 k++; 93 if(cnt>T/2)ok=1; 94 if(ok)ret=mid,l=mid+1; 95 else r=mid-1; 96 } 97 return ret; 98 } 99 100 int main() 101 { 102 // freopen("in.txt","r",stdin); 103 int i,j,cnt,ans,k,t; 104 char s[N]; 105 while(~scanf("%d",&T) && T) 106 { 107 n=0;cnt=130; 108 for(i=0;i<T;i++){ 109 scanf("%s",s); 110 for(j=0;s[j];j++){ 111 ma[n]=i; 112 num[n++]=s[j]-'a'+1; 113 } 114 ma[n]=i; 115 num[n++]=cnt++; 116 } 117 num[n]=0; 118 m=cnt; 119 build_sa(num,n+1,m); 120 getHeight(num,n); 121 122 ans=binary(0,1001); 123 if(ans){ 124 if(T==1){ 125 printf("%s\n\n",s); 126 continue; 127 } 128 mem(vis,0); 129 k=1;cnt=1; 130 vis[ma[sa[1]]]=1; 131 for(i=2;i<=n;i++){ 132 if(height[i]>=ans){ 133 if(vis[ma[sa[i]]]!=k)vis[ma[sa[i]]]=k,cnt++; 134 } 135 else { 136 if(cnt>T/2){ 137 for(j=sa[i-1],t=ans;t--;j++) 138 printf("%c",num[j]+'a'-1); 139 putchar('\n'); 140 } 141 k++;cnt=1; 142 vis[ma[sa[i]]]=k; 143 } 144 } 145 if(cnt>T/2){ 146 for(j=sa[i-1],t=ans;t--;j++) 147 printf("%c",num[j]+'a'-1); 148 putchar('\n'); 149 } 150 } 151 else printf("?\n"); 152 putchar('\n'); 153 } 154 return 0; 155 }