SPOJ 1812 多模式LCS

来源:互联网 发布:网络包年维护服务 编辑:程序博客网 时间:2024/06/05 06:28

题意: 给出多个串,求所有串的LCS。


题解:对第一个串创建SAM,其他串在上边跑,然后吧每个点更新出,模式串和匹配串在这一点向前最长匹配长度,那么所有船匹配完成之后,每个点取min,就得到了所有串在这一点的公共部分有多长,然后所有点取max得到答案。


注意:要更新处parent链上所有的点。


考虑样例:


acbbc

ac

bc

自动机为:


答案是1而不是0。


Code:

#include<bits/stdc++.h>using namespace std;const int maxn = 1e5+100;const int INF = 2147400000;char s[maxn];int len;int cntA[maxn];struct SAM{int cnt,last,nxt[maxn*2][26],fa[maxn*2],l[maxn*2],lcs[maxn*2],num[maxn*2],rk[maxn*2];void init(){cnt=last=1;memset(nxt[1],0,sizeof nxt[1]);fa[1]=l[1]=0;}void add(int c){int p = last;int np = ++cnt;l[np] = l[p]+1;last = np;while (p&&!nxt[p][c]){nxt[p][c]=np;p=fa[p];}if (!p){fa[np] =1;}else{int q = nxt[p][c];if (l[q]==l[p]+1){fa[np] =q;}else{int nq = ++cnt;memcpy(nxt[nq],nxt[q],sizeof nxt[q]);fa[nq] =fa[q];l[nq] =l[p]+1;fa[np]=fa[q]=nq;while (nxt[p][c]==q){nxt[p][c]=nq;p=fa[p];}}}}void build (){memset(cntA,0,sizeof cntA);for (int i=1;i<=cnt;i++){lcs[i] = INF;}for (int i=1;i<=cnt;i++){cntA[l[i]]++;}for (int i=1;i<=l[last];i++){cntA[i]+=cntA[i-1];}for (int i=1;i<=cnt;i++){rk[cntA[l[i]]--]=i;}}void query(){memset(num,0,sizeof num);int len = strlen(s);int now =1;int nowlen = 0;for (int i=0;i<len;i++){int c = s[i]-'a';if (nxt[now][c]){nowlen++;now = nxt[now][c];}else{while (now&&!nxt[now][c]){now = fa[now];}if (!now){now =1;nowlen =0;}else{nowlen = l[now]+1;now = nxt[now][c];}}num[now] = max(num[now],nowlen);}for (int i=cnt;i>=1;i--){int x = rk[i];num[fa[x]] = max(num[fa[x]],min(l[fa[x]],num[x]));}for (int i=1;i<=cnt;i++){lcs[i] = min(lcs[i],num[i]);}}int get_ans(){int res =0;for (int i=1;i<=cnt;i++){res = max(res,lcs[i]);}return res;}}sam;int main(){sam.init();scanf("%s",s);int len = strlen(s);for (int i=0;i<len;i++){sam.add(s[i]-'a');}sam.build();while (scanf("%s",s)!=EOF){sam.query();}printf("%d\n",sam.get_ans());return 0;}


原创粉丝点击