zoukankan      html  css  js  c++  java
  • BZOJ4698 SDOI2008Sandy的卡片(后缀自动机)

      差分后即求多串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
    ";
    #else
    	const char LL[]="%lld
    ";
    #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;
    }
    

      

  • 相关阅读:
    Windows下安装Redmine
    【精华】Linux/GNOME的小技巧
    Perl简单教程
    【转载】手把手教你配置Windows2003集群(图)
    Windows 7 下如何配置PHP网站运行环境
    常用的PHP数据库操作方法(MYSQL版)
    CentOS上搭建Nginx + Mono 运行 asp.net
    【视频】Win2003 iis 流媒体设置
    【实用】OS X Lion restore Recovery HD Manually 手工创建 OS X Lion 恢复分区
    【小结】CentOS Linux操作系统的设置:
  • 原文地址:https://www.cnblogs.com/Gloid/p/10805790.html
Copyright © 2011-2022 走看看