【SPOJ1811】Longest Common Substring
【SPOJ7258】Lexicographical Substring Search

【SPOJ1812】Longest Common Substring II

Zarxdy34 posted @ 2016年4月02日 13:10 in SPOJ with tags SAM , 538 阅读

  给第一个串建SAM,然后之后的每一个串都和第一个串匹配,对于每个状态记录当前串在当前状态下的LCS,最后把答案合并一下就好了。

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100010;

struct SAM
{
	struct State
	{
		int next[26];
		int link;
		int len;
	}st[maxn<<1];

	int last,cnt,n;
	int ccnt[maxn];
	int T[maxn<<1];
	int temp[maxn<<1],minl[maxn<<1];
	
	SAM() {last=cnt=1;}

	void Extend(int c)
	{
		int x=++cnt,p;n++;
		st[x].len=st[last].len+1;
		for (p=last;p && !st[p].next[c];p=st[p].link) st[p].next[c]=x;
		if (!p) st[x].link=1;
		else {
			int q=st[p].next[c];
			if (st[q].len==st[p].len+1) st[x].link=q;
			else {
				int v=++cnt;
				st[v]=st[q];
				st[v].len=st[p].len+1;
				for (;p && st[p].next[c]==q;p=st[p].link) st[p].next[c]=v;
				st[x].link=st[q].link=v;
			}
		}
		last=x;
	}

	void Topo()
	{
		for (int i=1;i<=cnt;i++) ccnt[st[i].len]++;
		for (int i=1;i<=n;i++) ccnt[i]+=ccnt[i-1];
		for (int i=1;i<=cnt;i++) T[ccnt[st[i].len]--]=i;
		for (int i=1;i<=cnt;i++) minl[i]=st[i].len;
	}

	int LCS(char *ch,int cn)
	{
		int res=0;
		memset(temp,0,sizeof(temp));
		for (int i=0,p=1,len=0;i<cn;i++)
		{
			int c=ch[i]-'a';
			while (p && !st[p].next[c]) p=st[p].link,len=st[p].len;
			if (!p) p=1,len=0;else p=st[p].next[c],len++;
			temp[p]=max(temp[p],len);
		}
		for (int i=cnt;i;i--)
		{
			int v=T[i];
			minl[v]=min(minl[v],temp[v]);
			res=max(res,minl[v]);
			if (temp[v]) temp[st[v].link]=max(temp[st[v].link],temp[v]);
		}
		return res;
	}
}M;

char ch[maxn];
int n,ans;

int main()
{
	scanf("%s",ch);
	n=strlen(ch);
	for (int i=0;i<n;i++) M.Extend(ch[i]-'a');
	M.Topo();
	ans=n;
	while (scanf("%s",ch)!=EOF) ans=M.LCS(ch,strlen(ch));
	printf("%d\n",ans);
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter