POJ 1225 Substrings

http://poj.org/problem?id=1226

题意:给定n个串。求一个最长的串,使得这个串或者其反串在每个串中都出现过?

思路:先在大串里面加入正反串,然后二分,判定即可。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 int num[200005],ws[200005],wv[200005],wb[200005],wa[200005];
 7 int n,m,rank[200005],sa[200005],h[200005],b[200005];
 8 int read(){
 9     int t=0,f=1;char ch=getchar();
10     while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
11     while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
12     return t*f;
13 }
14 bool cmp(int *r,int a,int b,int l){
15     return r[a]==r[b]&&r[a+l]==r[b+l];
16 }
17 void da(int *r,int *sa,int n,int m){
18     int *y=wb,*x=wa,*t,i,j,p;
19     for (i=0;i<m;i++) ws[i]=0;
20     for (i=0;i<n;i++) x[i]=r[i];
21     for (i=0;i<n;i++) ws[x[i]]++;
22     for (i=1;i<m;i++) ws[i]+=ws[i-1];
23     for (i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
24     for (p=1,j=1;p<n;m=p,j*=2){
25         for (p=0,i=n-j;i<n;i++) y[p++]=i;
26         for (i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;
27         for (i=0;i<m;i++) ws[i]=0;
28         for (i=0;i<n;i++) wv[i]=x[y[i]];
29         for (i=0;i<n;i++) ws[wv[i]]++;
30         for (i=1;i<m;i++) ws[i]+=ws[i-1];
31         for (i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
32         for (t=x,x=y,y=t,i=1,p=1,x[sa[0]]=0;i<n;i++)
33          x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
34     }
35 }
36 void cal(int *r,int n){
37     int i,j,k=0;
38     for (i=1;i<=n;i++) rank[sa[i]]=i;
39     for (i=0;i<n;h[rank[i++]]=k)
40      for (k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
41 }
42 bool check(int x){
43     int L,R;
44     int hash[105];
45     for (int i=1;i<=n;i++){
46         L=i;
47         while (L<=n&&h[L]<x) L++;
48         if (L>n) break;
49         R=L;
50         while (R<=n&&h[R]>=x) R++;
51         memset(hash,0,sizeof hash);
52         for (int j=L-1;j<=R-1;j++)
53          if (b[sa[j]]<=m)
54           hash[b[sa[j]]]=1;
55         int j=0;
56         for (j=1;j<=m;j++)
57          if (!hash[j]) break;
58         if (j>m) return 1; 
59         i=R; 
60     }
61     return 0;
62 }
63 void solve(){
64     int l=0,r=100,ans;
65     while (l<=r){
66         int mid=(l+r)>>1;
67         if (check(mid)) ans=mid,l=mid+1;
68         else r=mid-1;
69     }
70     printf("%d\n",ans);
71 }
72 int main(){
73     int T=read();
74     char s[200005];
75     while (T--){
76         m=read();n=0;int sx=130;
77         for (int i=1;i<=m;i++){
78             scanf("%s",s);
79             int len=strlen(s);
80             for (int j=0;j<len;j++)
81              num[n]=s[j],b[n++]=i;
82             num[n]=sx++;b[n++]=n+1; 
83             for (int j=len-1;j>=0;j--)
84              num[n]=s[j],b[n++]=i;
85             num[n]=sx++;b[n++]=n+1; 
86         }
87         num[n]=0;b[n]=n+1;
88         da(num,sa,n+1,sx+10);
89         cal(num,n);
90         solve();
91     }
92 }

 

posted @ 2016-07-03 22:09  GFY  阅读(164)  评论(0编辑  收藏  举报