把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

SP1812 LCS2 - Longest Common Substring II

题面传送门
先来考虑两个字符串的最长公共子串怎么求。
考虑SAM有一个性质:源点到任意点的任意路径都是原串的一个子串。
这个性质就可以搞了。
首先对于第一个串建立AC自动机,然后让第二个串在第一个串上跑匹配。
这样就可以计算答案了。
但是对于多个串怎么办呢?
可以在每个节点上都对于每个串计算答案并取\(\min\)
注意一个串匹配到节点\(x\)\(x\)在parent树上的祖先都是可以匹配的。
所以每个串做完要统一往上推。
code:

#include<cstdio>
#include<cstring>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
#define l(x) x<<1
#define r(x) x<<1|1
#define N 500039
#define ll long long
#define ui unsigned int
using namespace std;
int n,m,k,x,y,z,ans,tot,pus;char a[13][N];
struct SAM{
	int fa[N],son[N][26],len[N],cur,pus,p,now,last=1,cnt=1,g[N],h[N],f[N],b[N],m,i;
	I void insert(int x){
		p=last;now=last=++cnt;len[now]=len[p]+1;while(p&&!son[p][x]) son[p][x]=now,p=fa[p];
		if(!p) return  (void)(fa[now]=1);
		cur=son[p][x];if(len[cur]==len[p]+1) fa[now]=cur;
		else{
			fa[pus=++cnt]=fa[cur];memcpy(son[pus],son[cur],sizeof(son[pus]));len[pus]=len[p]+1;fa[now]=fa[cur]=pus;
			while(p&&son[p][x]==cur) son[p][x]=pus,p=fa[p];
		} 
	}
	I void sort(){
		for(i=1;i<=cnt;i++)f[len[i]]++;
		for(i=1;i<=cnt;i++) f[i]+=f[i-1];
		for(i=cnt;i;i--) b[f[len[i]]--]=i;
	}
	I void solve(char *a){
		for(i=1;i<=cnt;i++)h[i]=0; 
 		for(m=strlen(a+1),p=1,tot=0,i=1;i<=m;i++){
			now=a[i]-'a';if(son[p][now]) p=son[p][now],tot++;
			else{
				while(p&&!son[p][now]) p=fa[p];tot=len[p]+1;
				p=son[p][now];!p&&(p=1,tot=0);
			}
			h[p]=max(h[p],tot);
		}
		for(i=cnt;i;i--) now=b[i],h[fa[now]]=max(h[fa[now]],h[now]),g[now]=min(g[now],h[now]);
	}
}s;
int main(){
	freopen("1.in","r",stdin);
	register int i;for(n=1;~scanf("%s",a[n]+1);n++);m=strlen(a[1]+1);for(i=1;i<=m;i++) s.insert(a[1][i]-'a');
	for(i=1;i<=s.cnt;i++)s.g[i]=s.len[i];s.sort();for(i=2;i<n;i++)s.solve(a[i]);for(i=1;i<=s.cnt;i++)ans=max(ans,s.g[i]);printf("%d\n",ans);
}
posted @ 2021-03-25 20:31  275307894a  阅读(29)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end