spoj 1812 LCS2(SAM+DP)
求若干个串的最长公共子串。
SAM+DP
先拿个串建个SAM,然后用后面的串匹配,每次将所有的匹配长度记录在状态上取min,然后对所有状态取max即答案。
需要更新fa,因为fa[p]一定比p更优,但匹配的时候可能只更新了p而没有更新fa[p],所以还需要递推一边。
注意mn[p]初始化为l[p]
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 const int N = 5*1e5+10; 6 7 char s[N]; 8 int sz,last,root,l[N],ch[N][26],fa[N],mn[N],mx[N]; 9 int b[N],cnt[N]; 10 void add(int x) { 11 int c=s[x]-'a'; 12 int p=last,np=++sz; last=np; 13 l[np]=mn[np]=x+1; 14 for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np; 15 if(!p) fa[np]=root; 16 else { 17 int q=ch[p][c]; 18 if(l[p]+1==l[q]) fa[np]=q; 19 else { 20 int nq=++sz; l[nq]=mn[nq]=l[p]+1; 21 memcpy(ch[nq],ch[q],sizeof(ch[q])); 22 fa[nq]=fa[q]; 23 fa[np]=fa[q]=nq; 24 for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 25 } 26 } 27 } 28 29 int main() { 30 root=last=++sz; 31 scanf("%s",s); 32 int len=strlen(s); 33 for(int i=0;i<len;i++) add(i); 34 for(int i=1;i<=sz;i++) cnt[l[i]]++; 35 for(int i=1;i<=len;i++) cnt[i]+=cnt[i-1]; 36 for(int i=1;i<=sz;i++) b[cnt[l[i]]--]=i; 37 while(scanf("%s",s)==1) { 38 int p=root; len=0; 39 for(int i=0;s[i];i++) { 40 int c=s[i]-'a'; 41 if(ch[p][c]) { len++; p=ch[p][c]; } 42 else { 43 while(p&&!ch[p][c]) p=fa[p]; 44 if(!p) { len=0; p=root; } 45 else { len=l[p]+1; p=ch[p][c]; } 46 } 47 if(len>mx[p]) mx[p]=len; 48 } 49 for(int i=sz;i;i--) { 50 p=b[i]; 51 if(mx[p]<mn[p]) mn[p]=mx[p]; 52 if(fa[p] && mx[fa[p]]<mx[p]) mx[fa[p]]=mx[p]; 53 mx[p]=0; 54 } 55 } 56 int ans=0; 57 for(int i=1;i<=sz;i++) 58 if(mn[i]>ans) ans=mn[i]; 59 printf("%d",ans); 60 return 0; 61 }
先将一个串建SAM,然后用后面的串去匹配,对于每一个串,保存最大值,对于不同的串,更新最小值。
SAM结点多两个值,ml表示多个串的最小值,nl表示当前串匹配的最大值。
1 #include <iostream> 2 #include <string.h> 3 #include <algorithm> 4 #include <stdio.h> 5 6 using namespace std; 7 const int N=250005; 8 9 struct State 10 { 11 State *pre,*go[26]; 12 int step,nl,ml; 13 void clear() 14 { 15 pre=0; 16 step=0; 17 memset(go,0,sizeof(go)); 18 } 19 }*root,*last; 20 21 State statePool[N*2],*b[2*N],*cur; 22 23 void init() 24 { 25 cur=statePool; 26 root=last=cur++; 27 root->clear(); 28 } 29 30 void Insert(int w) 31 { 32 State *p=last; 33 State *np=cur++; 34 np->clear(); 35 np->step=np->ml=p->step+1; 36 while(p&&!p->go[w]) 37 p->go[w]=np,p=p->pre; 38 if(p==0) 39 np->pre=root; 40 else 41 { 42 State *q=p->go[w]; 43 if(p->step+1==q->step) 44 np->pre=q; 45 else 46 { 47 State *nq=cur++; 48 nq->clear(); 49 memcpy(nq->go,q->go,sizeof(q->go)); 50 nq->step=nq->ml=p->step+1; 51 nq->pre=q->pre; 52 q->pre=nq; 53 np->pre=nq; 54 while(p&&p->go[w]==q) 55 p->go[w]=nq, p=p->pre; 56 } 57 } 58 last=np; 59 } 60 61 char str[N]; 62 int cnt[N]; 63 64 int main() 65 { 66 int n,m; 67 scanf("%s",str); 68 n=strlen(str); 69 init(); 70 for(int i=0; i<n; i++) 71 Insert(str[i]-'a'); 72 for(State *p=statePool; p!=cur; p++) 73 cnt[p->step]++; 74 for(int i=1; i<=n; i++) 75 cnt[i]+=cnt[i-1]; 76 for(State *p=statePool; p!=cur; p++) 77 b[--cnt[p->step]]=p; 78 while(~scanf("%s",str)) 79 { 80 int len=0; 81 m=strlen(str); 82 State *p=root; 83 for(int i=0; i<m; i++) 84 { 85 int x=str[i]-'a'; 86 if(p->go[x]) 87 { 88 len++; 89 p=p->go[x]; 90 } 91 else 92 { 93 while(p&&!p->go[x]) p=p->pre; 94 if(!p) p=root,len=0; 95 else len=p->step+1,p=p->go[x]; 96 } 97 if(len>p->nl) p->nl=len; 98 } 99 int num=cur-statePool; 100 for(int i=num-1;i>=0;i--) 101 { 102 p=b[i]; 103 if(p->ml>p->nl) p->ml=p->nl; 104 if(p->pre&&p->pre->nl<p->nl) p->pre->nl=p->nl; 105 p->nl=0; 106 } 107 } 108 int ans=0; 109 for(State *p=statePool;p!=cur;p++) 110 if(p->ml>ans) ans=p->ml; 111 printf("%d\n",ans); 112 return 0; 113 }