POJ-3294 Life Forms 后缀数组

  题目链接: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 }

 

posted @ 2013-04-25 23:58  zhsl  阅读(237)  评论(0编辑  收藏  举报