【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....

posted @ 2015-01-12 20:32  iwtwiioi  阅读(324)  评论(0编辑  收藏  举报