题意
求出多个串的最长公共子串。
分析
刚学SAM想做这个题的话最好先去做一下那道codevs3160。求两个串的LCS应该怎么求?把一个串s1建自动机,然后跑另一个串s2,然后找出s2每个前缀的最长公共后缀。那么多个的时候,我们也用这种类似的方法,但是我们求最长公共后缀的时候要求第一个串的。我们把其中一个串建SAM,然后把其他的串都在上面跑,维护两个值,Max[u]和Min[u]。自动机中每个状态u的Right存的是结尾集合。那么对于一个字符串,我们可以求出他和自动机中每个状态的最长公共后缀。然后,我们通过Max[fa[u]]=max(Max[fa[u]],Max[u])来确定左右状态的最长公共后缀,然后更新Min[o]。
下面的代码没有AC,但是我找了好久BUG没找到··如果有人看完并且找到了bug麻烦跟我说一下万分感谢!
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=300000+100; 8 char s[maxn]; 9 struct state{ 10 int len,link; 11 int next[26]; 12 }st[2*maxn]; 13 int n,last,cur,sz; 14 int Min[2*maxn],Max[2*maxn],c[2*maxn]; 15 16 void init(){ 17 sz=1; 18 cur=last=0; 19 st[0].link=-1; 20 st[0].len=0; 21 } 22 23 void build_sam(int c){ 24 cur=sz++; 25 st[cur].len=st[last].len+1; 26 Min[cur]=st[cur].len; 27 int p; 28 for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link) 29 st[p].next[c]=cur; 30 if(p==-1) 31 st[cur].link=0; 32 else{ 33 int q=st[p].next[c]; 34 if(st[q].len==st[p].len+1) 35 st[cur].link=q; 36 else{ 37 int clone=sz++; 38 st[clone].len=st[p].len+1; 39 Min[clone]=st[clone].len; 40 st[clone].link=st[q].link; 41 for(int i=0;i<26;i++) 42 st[clone].next[i]=st[q].next[i]; 43 for(;p!=-1&&st[p].next[c]==q;p=st[p].link) 44 st[p].next[c]=clone; 45 st[cur].link=st[q].link=clone; 46 } 47 } 48 last=cur; 49 } 50 51 int cmp(int a,int b){ 52 return st[a].len<st[b].len; 53 } 54 55 int main(){ 56 scanf("%s",s); 57 n=strlen(s); 58 init(); 59 60 for(int i=0;i<n;i++) 61 build_sam(s[i]-'a'); 62 for(int i=0;i<sz;i++) 63 c[i]=i; 64 sort(c,c+sz,cmp); 65 66 while(scanf("%s",s)!=EOF){ 67 n=strlen(s); 68 int u=0,len=0; 69 for(int i=0;i<n;i++){ 70 int c=s[i]-'a'; 71 if(u!=-1&&st[u].next[c]==0) 72 u=st[u].link,len=st[u].len; 73 if(u==-1) 74 u=0,len=0; 75 else{ 76 u=st[u].next[c]; 77 len++; 78 Max[u]=max(Max[u],len); 79 } 80 } 81 82 for(int i=sz-1;i>=0;i--){ 83 int o=c[i]; 84 Min[o]=min(Min[o],Max[o]); 85 if(st[o].link!=-1){ 86 Max[st[o].link]=max(Max[st[o].link],Max[o]); 87 } 88 Max[o]=0; 89 } 90 } 91 int ans=0; 92 for(int i=0;i<sz;i++){ 93 ans=max(ans,Min[i]); 94 } 95 printf("%d\n",ans); 96 97 return 0; 98 }