【BZOJ 2946】 2946: [Poi2000]公共串 (SAM)
2946: [Poi2000]公共串
Time Limit: 3 Sec Memory Limit: 128 MB
Submit: 1063 Solved: 469Description
给出几个由小写字母构成的单词,求它们最长的公共子串的长度。任务:l 读入单词l 计算最长公共子串的长度l 输出结果Input
文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。Output
仅一行,一个整数,最长公共子串的长度。Sample Input
3
abcb
bca
acbc
Sample Output
2HINT
Source
【分析】
重新学一次SAM,从刷水题开始。
同spoj1812。用第一个串建sam,然后用其他的串跑,ans存在那个点那里,做完一个串的时候还要根据parent边的拓扑序更新该点ans,最后取min即可。
当然后缀数组也是可以的。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 2010 8 9 int mymax(int x,int y) {return x>y?x:y;} 10 int mymin(int x,int y) {return x<y?x:y;} 11 12 struct node 13 { 14 int pre,son[30],step; 15 // node() {pre=step=0;memset(son,0,sizeof(son));} 16 }t[Maxn*2]; 17 int ans[Maxn*2],ad[Maxn*2]; 18 19 struct sam 20 { 21 int last,tot; 22 /*void upd(int x) 23 { 24 memset(t[x].son,0,sizeof(t[x].son)); 25 }*/ 26 void extend(int k) 27 { 28 int np=++tot,p=last; 29 t[np].step=t[last].step+1; 30 while(p&&!t[p].son[k]) 31 { 32 t[p].son[k]=np; 33 p=t[p].pre; 34 } 35 if(!p) t[np].pre=1; 36 else 37 { 38 int q=t[p].son[k]; 39 if(t[q].step==t[p].step+1) t[np].pre=q; 40 else 41 { 42 int nq=++tot;//upd(tot); 43 t[nq].step=t[p].step+1; 44 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son)); 45 t[nq].pre=t[q].pre; 46 t[q].pre=t[np].pre=nq; 47 while(p&&t[p].son[k]==q) 48 { 49 t[p].son[k]=nq; 50 p=t[p].pre; 51 } 52 } 53 } 54 last=np; 55 } 56 57 }sam; 58 59 char s[10],ss[Maxn]; 60 61 int main() 62 { 63 int n;scanf("%d",&n); 64 scanf("%s",s); 65 sam.last=sam.tot=1; 66 int l=strlen(s); 67 for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1); 68 memset(ans,63,sizeof(ans)); 69 for(int i=2;i<=n;i++) 70 { 71 scanf("%s",s); 72 l=strlen(s); 73 int nw=1,sp=0; 74 for(int j=1;j<=sam.tot;j++) ad[j]=0; 75 for(int j=0;j<l;j++) 76 { 77 int ind=s[j]-'a'+1; 78 while(nw&&!t[nw].son[ind]) nw=t[nw].pre,sp=t[nw].step; 79 if(t[nw].son[ind]) sp++,nw=t[nw].son[ind]; 80 else nw=1,sp=0; 81 ad[nw]=mymax(ad[nw],sp); 82 } 83 for(int i=sam.tot;i>=1;i--) ad[t[i].pre]=mymax(ad[t[i].pre],mymin(ad[i],t[t[i].pre].step)); 84 for(int i=sam.tot;i>=1;i--) ans[i]=mymin(ans[i],ad[i]); 85 } 86 int mx=0; 87 for(int i=1;i<=sam.tot;i++) if(ans[i]<=sam.tot) mx=mymax(mx,ans[i]); 88 printf("%d\n",mx); 89 return 0; 90 }
2017-04-17 10:21:42