首页 > 代码库 > 【BZOJ】2946: [Poi2000]公共串

【BZOJ】2946: [Poi2000]公共串

http://www.lydsy.com/JudgeOnline/problem.php?id=2946

题意:给n个串,求最大公共子串。(1<=n<=5,每个串长度<=2000)

#include <bits/stdc++.h>using namespace std;const int N=2005<<1;struct sam {	int cnt, root, last, l[N], c[N][26], f[N], p[N], mx[N], mxl[N];	sam() { cnt=0; root=last=++cnt; }	void add(int x) {		int now=last, a=++cnt; last=a;		l[a]=l[now]+1;		for(; now && !c[now][x]; now=f[now]) c[now][x]=a;		if(!now) { f[a]=root; return; }		int q=c[now][x];		if(l[q]==l[now]+1) { f[a]=q; return; }		int b=++cnt;		memcpy(c[b], c[q], sizeof c[q]);		l[b]=l[now]+1;		f[b]=f[q];		f[q]=f[a]=b;		for(; now && c[now][x]==q; now=f[now]) c[now][x]=b;	}	void build(char *s) {		int len=strlen(s);		for(int i=0; i<len; ++i) add(s[i]-‘a‘);		for(int i=1; i<=cnt; ++i) mx[l[i]]++;		for(int i=1; i<=len; ++i) mx[i]+=mx[i-1];		for(int i=1; i<=cnt; ++i) p[mx[l[i]]--]=i;		for(int i=1; i<=cnt; ++i) mx[i]=l[i];	}	void find(char *s) {		int x, now=root, t=0, len=strlen(s);		for(int i=0; i<len; ++i) {			x=s[i]-‘a‘;			if(c[now][x]) ++t, now=c[now][x];			else {				while(now && !c[now][x]) now=f[now];				if(!now) t=0, now=root;				else t=l[now]+1, now=c[now][x];			}			mxl[now]=max(mxl[now], t);		}		for(int i=cnt; i; --i) {			x=p[i];			mx[x]=min(mx[x], mxl[x]);			if(mxl[x] && f[x]) mxl[f[x]]=l[f[x]];			mxl[x]=0;		}	}	int getans() {		int ret=0;		for(int i=1; i<=cnt; ++i) ret=max(ret, mx[i]);		return ret;	}}solver;char s[N];int main() {	int n;	scanf("%d", &n);	scanf("%s", s);	solver.build(s); --n;	while(n--) scanf("%s", s), solver.find(s);	printf("%d\n", solver.getans());	return 0;}

  


 

复习了下sam....

【BZOJ】2946: [Poi2000]公共串