1. 程式人生 > >BZOJ4698 SDOI2008Sandy的卡片(後綴自動機)

BZOJ4698 SDOI2008Sandy的卡片(後綴自動機)

tchar namespace mat ace spa sandy 前綴 light ||

  差分後即求多串LCS。先考慮兩個串怎麽做。對第一個串建SAM,第二個串在上面跑即可,任意時刻走到的節點表示的都是第二個串的當前前綴在第一個串中出現的最長的後綴,具體計算長度時每走一個字符長度+1,跳fail時將長度重設為當前節點maxlen即可。

  擴展到多串,同樣對第一個串建SAM,後面每個串在上面跑一遍,每走到一個節點就記錄當前匹配長度,每個節點對所有串取min,再在所有節點中找max即可。註意每個串跑完時都要按parent樹更新一遍節點的記錄值,因為能在某點匹配就一定可以在它的所有父親處以最長長度匹配。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
#define N 2010
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
	while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,a[N][N],cnt=1,last=1,len[N],fail[N],u[N],v[N],id[N];
map<int,int> son[N];
void ins(int c,int n)
{
	int x=++cnt,p=last;last=x;len[x]=len[p]+1;
	while (!son[p][c]) son[p][c]=x,p=fail[p];
	if (!p) fail[x]=1;
	else
	{
		int q=son[p][c];
		if (len[q]==len[p]+1) fail[x]=q;
		else
		{
			int y=++cnt;
			len[y]=len[p]+1;
			son[y]=son[q];
			fail[y]=fail[q],fail[x]=fail[q]=y;
			while (son[p][c]==q) son[p][c]=y,p=fail[p];
		}
	}
}
void run(int n,int *a)
{
	memset(v,0,sizeof(v));
	int k=1,l=0;
	for (int i=1;i<=n;i++)
	{
		while (!son[k][a[i]]&&k) k=fail[k],l=len[k];
		if (!k) k=1,l=0;
		else l++,k=son[k][a[i]],v[k]=max(v[k],l);
	}
	for (int i=1;i<=cnt;i++) if (v[id[i]]) v[fail[id[i]]]=len[fail[id[i]]];
	for (int i=1;i<=cnt;i++) u[i]=min(u[i],v[i]);
}
bool cmp(const int&a,const int&b)
{
	return len[a]>len[b];
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("bzoj4698.in","r",stdin);
	freopen("bzoj4698.out","w",stdout);
	const char LL[]="%I64d\n";
#else
	const char LL[]="%lld\n";
#endif
	n=read();
	for (int i=1;i<=n;i++)
	{
		a[i][0]=read();
		for (int j=1;j<=a[i][0];j++) a[i][j]=read();
		for (int j=a[i][0];j>=1;j--) a[i][j]-=a[i][j-1];
		for (int j=1;j<a[i][0];j++) a[i][j]=a[i][j+1];
		a[i][0]--;
	}
	for (int i=1;i<=a[1][0];i++) ins(a[1][i],i);
	memset(u,42,sizeof(u));
	for (int i=1;i<=cnt;i++) id[i]=i;
	sort(id+1,id+cnt+1,cmp);
	for (int i=2;i<=n;i++) run(a[i][0],a[i]);
	int ans=0;
	for (int i=1;i<=cnt;i++) ans=max(ans,min(len[i],u[i]));
	cout<<ans+1;
	return 0;
}

  

BZOJ4698 SDOI2008Sandy的卡片(後綴自動機)