SPOJ1811 LCS SAM
后缀自动机简单题。
其主要思路是,先对第一个字符串建立后缀自动机,把第二个串放在上面匹配,
若当前状态s有字符x的转移,直接转移len=step+1。
若当前状态s没有向字符x的转移,退回pres检查是否有转移,
若没有,则继续退回,否则转移到节点y,len=stepy+1。
以上思路主要利用的是关于pre节点的性质,由于pre节点的right集合是其子节点的right集合的并集,且max(pre)=min(s)-1.
所以从pre节点往上跳的时候,就能找到最长的后缀相同的部分的节点。(不知道这么说对不对)。
与KMP算法的很像。
可以参考这篇博客
1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<string>
5 #include<cstring>
6 #include<cmath>
7 #include<ctime>
8 #include<algorithm>
9 #include<iomanip>
10 #include<set>
11 #include<map>
12 #include<queue>
13 using namespace std;
14 #define mem1(i,j) memset(i,j,sizeof(i))
15 #define mem2(i,j) memcpy(i,j,sizeof(i))
16 #define LL long long
17 #define up(i,j,n) for(int i=(j);i<=(n);i++)
18 #define FILE "dealing"
19 #define poi vec
20 #define eps 1e-10
21 #define db double
22 const int maxn=250100,inf=1000000000,mod=1000000007;
23 int read(){
24 int x=0,f=1,ch=getchar();
25 while(x<'0'||x>'9'){if(ch=='-')f=-1;ch=getchar();}
26 while(x<='9'&&x>='0'){x=(x<<1)+(x<<3)+ch-'0',ch=getchar();}
27 return f*x;
28 }
29 bool cmax(int& a,int b){return a<b?a=b,true:false;}
30 namespace sam{
31 const int maxn=505000;
32 int pre[maxn],c[maxn][26],len[maxn],now,cnt,np,p,q,nq,Len;
33 void clear(){mem1(c,0);mem1(len,0);mem1(pre,0);cnt=1,now=1;}
34 void expend(int x){
35 np=++cnt;len[np]=len[now]+1;p=now;now=np;
36 while(p&&!c[p][x])c[p][x]=np,p=pre[p];
37 if(!p)pre[np]=1;
38 else {
39 q=c[p][x];
40 if(len[q]==len[p]+1)pre[np]=q;
41 else {
42 len[nq=++cnt]=len[p]+1;
43 pre[nq]=pre[q];
44 pre[q]=pre[np]=nq;
45 mem2(c[nq],c[q]);
46 while(p&&c[p][x]==q)c[p][x]=nq,p=pre[p];
47 }
48 }
49 }
50 int walk(int x){
51 while(!c[now][x]&&pre[now])now=pre[now],Len=len[now];
52 if(!c[now][x])return 0;
53 now=c[now][x];Len++;return Len;
54 }
55 void build(char* s){
56 int n=strlen(s+1);
57 up(i,1,n)expend(s[i]-'a');
58 }
59 };
60 char s[maxn];
61 int main(){
62 freopen(FILE".in","r",stdin);
63 freopen(FILE".out","w",stdout);
64 sam::clear();
65 scanf("%s",s+1);
66 sam::build(s);
67 scanf("%s",s+1);
68 int n=strlen(s+1);
69 int ans=0;sam::now=1;sam::Len=0;
70 up(i,1,n)cmax(ans,sam::walk(s[i]-'a'));
71 cout<<ans<<endl;
72 return 0;
73 }