POJ - 3294 Life Forms

传送门:POJ - 3294   (类似题目POJ - 3450)

题意:给你n个字符串,求在不小于k/2个字符串中出现过的最长子串。

题解:首先将n个字符串连起来,中间用不一样且没出现过的字符连起来(这个地方让我wa了好几发!!),然后二分字串的长度,将后缀分成若干组,判断每组的后缀是否在不小于k个的原串中出现过,数组sum记录每个最长字符串在原串中出现的位置sa[i]。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<queue>
  4 #include<iostream>
  5 #include<cmath>
  6 #include<cstring>
  7 using namespace std;
  8 
  9 const int maxn = 1000100;
 10 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
 11 int rnk[maxn],height[maxn],sum[maxn];
 12 char s[maxn];
 13 int r[maxn],n,pos=0,len[110],vis[110],ans=0,L,be[maxn];
 14 
 15 //sa:字典序中排第i位的起始位置在str中第sa[i]  sa[1~n]为有效值
 16 
 17 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值
 18 
 19 //height:字典序排i和i-1的后缀的最长公共前缀  height[2~n]为有效值,第二个到最后一个
 20 
 21 int cmp(int *r,int a,int b,int k)
 22 {
 23     return r[a]==r[b]&&r[a+k]==r[b+k];
 24 }
 25 
 26 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
 27 {
 28     int i,j,p,*x=wa,*y=wb,*t;
 29     for(i=0; i<m; i++)  wsf[i]=0;
 30     for(i=0; i<=n; i++)  wsf[x[i]=r[i]]++;
 31     for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
 32     for(i=n; i>=0; i--)  sa[--wsf[x[i]]]=i;
 33     p=1;
 34     j=1;
 35     for(; p<=n; j*=2,m=p){
 36         for(p=0,i=n+1-j; i<=n; i++)  y[p++]=i;
 37         for(i=0; i<=n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;
 38         for(i=0; i<=n; i++)  wv[i]=x[y[i]];
 39         for(i=0; i<m; i++)  wsf[i]=0;
 40         for(i=0; i<=n; i++)  wsf[wv[i]]++;
 41         for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
 42         for(i=n; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];
 43         swap(x,y);
 44         x[sa[0]]=0;
 45         for(p=1,i=1; i<=n; i++)
 46             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
 47     }
 48 }
 49 
 50 void getheight(int *r,int n)//n为添加0后的总长
 51 {
 52     int i,j,k=0;
 53     for(i=1; i<=n; i++)  rnk[sa[i]]=i;
 54     for(i=0; i<n; i++){
 55         if(k)
 56             k--;
 57         else
 58             k=0;
 59         j=sa[rnk[i]-1];
 60         while(r[i+k]==r[j+k])
 61             k++;
 62         height[rnk[i]]=k;
 63     }
 64 }
 65 
 66 bool check(int k)
 67 {
 68     int cnt=0,p=0;
 69     memset(vis,0,sizeof(vis));
 70     for(int i=1;i<=L;i++){
 71         if(height[i]>=k){
 72             if(!vis[be[sa[i]]]) cnt++;
 73             vis[be[sa[i]]]=1;
 74             if(!vis[be[sa[i-1]]]) cnt++;
 75             vis[be[sa[i-1]]]=1;
 76         }
 77         else{
 78             if(cnt>n/2) sum[p++]=sa[i-1];
 79             cnt=0;
 80             memset(vis,0,sizeof(vis));
 81         }
 82     }
 83     if(cnt>n/2) sum[p++]=sa[L];
 84     cnt=0;
 85     if(p) ans=p;
 86     if(p) return 1;
 87     return 0;
 88 }
 89 
 90 int main()
 91 {
 92     ios::sync_with_stdio(false);
 93     cin.tie(0);
 94     cout.tie(0);
 95     int t=0;
 96     while(cin>>n&&n){
 97         L=0;
 98         for(int i=1;i<=n;i++){
 99             cin>>s+L;
100             int p=strlen(s+L);
101             for(int j=0;j<p;j++){
102                 r[j+L]=s[j+L]-'A'+1;
103                 be[j+L]=i;
104             }
105             L+=p;
106             len[i]=L;
107             if(i!=n){
108                 r[L]=100+i;
109                 be[L]=i;
110                 L++;
111             }
112         }
113         r[L]=0;
114         getsa(r,sa,L,300);
115         getheight(r,L);
116         int l=1,r=L;
117         ans=0;
118         while(l<=r){
119             int mid=l+r>>1;
120             if(check(mid)){
121                 l=mid+1;
122             }
123             else r=mid-1;
124         }
125         if(t) cout<<endl;
126         t=1;
127         if(l==1) cout<<"?"<<endl;
128         for(int i=0;i<ans;i++){
129             for(int j=sum[i];j<sum[i]+l-1;j++){
130                 cout<<s[j];
131             }
132             cout<<endl;
133         }
134     }
135     return 0;
136 }

 

posted @ 2020-04-06 21:47  只能过样例嘤嘤嘤  阅读(222)  评论(0编辑  收藏  举报

……