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 }
View Code

 

posted @ 2017-02-20 13:49  CHADLZX  阅读(248)  评论(0编辑  收藏  举报