标签:匹配 cpp const blog ace dong 字符 bit 最大匹配
原文链接http://www.cnblogs.com/zhouzhendong/p/8982484.html
求若干$(若干<10)$个字符串的最长公共连续子串长度。
串长$\leq 100000$
建议在做本题之前,先去做SPOJ LCS,本题是其升级版。
题解链接 - SPOJ LCS - http://www.cnblogs.com/zhouzhendong/p/8982392.html
对于本题,我们只需要保持一下之后每一个串在第一个串的$SAM$的每一个状态上的最大匹配长度,然后最后对于每一个状态,取$min(该状态的Max值,其他所有字符串在该状态上面的最大匹配长度的最小值)$即可。
于是,我们先像SPOJ LCS一样,让所有串都走一遍,然后记录一下值。
注意到,每一个状态的结果都会对其$fa$做贡献。
于是我们可以基数排序预处理拓扑序,然后逆序更新即可。
#include <bits/stdc++.h> using namespace std; const int N=200005; int n,m=0,last=1,size=1,Max[15][N]; int id[N],tax[N]; char s[N]; struct SAM{ int Next[26],fa,Max; }t[N]; void expend(int c){ int p=last,np=++size,q,nq; t[np].Max=t[p].Max+1; for (;!t[p].Next[c];p=t[p].fa) t[p].Next[c]=np; q=t[p].Next[c]; if (t[q].Max==t[p].Max+1) t[np].fa=q; else { nq=++size; t[nq]=t[q],t[nq].Max=t[p].Max+1; t[q].fa=t[np].fa=nq; for (;t[p].Next[c]==q;p=t[p].fa) t[p].Next[c]=nq; } last=np; } int main(){ t[0].Max=-1; for (int i=0;i<26;i++) t[0].Next[i]=1; gets(s); n=strlen(s); for (int i=0;i<n;i++) expend(s[i]-‘a‘); for (int i=1;i<=size;i++) tax[t[i].Max]++; for (int i=1;i<=size;i++) tax[i]+=tax[i-1]; for (int i=1;i<=size;i++) id[tax[t[i].Max]--]=i; while (gets(s)&&strlen(s)){ n=strlen(s); for (int i=0,now=1,len=0;i<n;i++){ int c=s[i]-‘a‘; if (t[now].Next[c]){ len++; now=t[now].Next[c]; Max[m][now]=max(Max[m][now],len); continue; } while (!t[now].Next[c]) now=t[now].fa; len=t[now].Max+1; now=t[now].Next[c]; Max[m][now]=max(Max[m][now],len); } for (int i=size;i>=1;i--) Max[m][t[id[i]].fa]=max(Max[m][t[id[i]].fa],Max[m][id[i]]); m++; } int ans=0; for (int i=1;i<=size;i++){ int now=t[i].Max; for (int j=0;j<m;j++) now=min(now,Max[j][i]); ans=max(ans,now); } printf("%d",ans); return 0; }
SPOJ LCS2 - Longest Common Substring II 字符串 SAM
标签:匹配 cpp const blog ace dong 字符 bit 最大匹配
原文地址:https://www.cnblogs.com/zhouzhendong/p/8982484.html