[BZOJ4698][SDOI2008]Sandy的卡片(后缀自动机)

差分之后就是求多串LCS。

对其中一个串建SAM,然后把其它串放在上面跑。

对SAM上的每个状态都用f[x]记录这个状态与当前串的最长匹配长度,res[x]是对每次的f[x]取最小值。答案就是res[]的最大值。

考虑f[x]的求法,把s[]放在SAM上跑时,若下一个能正常匹配(即son[x][c]!=0)则直接len++,否则用经典的跳父亲,找到第一个son[k][c]!=0的点k,len=mx[k]+1,x=son[k][c]。
每次更新最终匹配到的状态的f[]。同时注意到出现次数可以向父亲传递,于是Radixsort之后经典DP转移最长长度即可。

 1 #include<map>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 typedef long long ll;
 7 using namespace std;
 8 
 9 const int N=500010;
10 int n,m,x,len,fir,lst=1,cnt=1,ans,res[N],s[N],f[N],mx[N],fa[N],c[N],q[N];
11 map<int,int>son[N];
12 
13 void ext(int c){
14     int p=lst,np=lst=++cnt; mx[np]=mx[p]+1;
15     while (p && !son[p][c]) son[p][c]=np,p=fa[p];
16     if (!p) fa[np]=1;
17     else{
18         int q=son[p][c];
19         if (mx[q]==mx[p]+1) fa[np]=q;
20         else{
21             int nq=++cnt; mx[nq]=mx[p]+1; son[nq]=son[q];
22             while (p && son[p][c]==q) son[p][c]=nq,p=fa[p];
23             fa[nq]=fa[q]; fa[q]=fa[np]=nq;
24         }
25     }
26 }
27 
28 void Radix(){
29     rep(i,1,cnt) c[mx[i]]++;
30     rep(i,1,cnt) c[i]+=c[i-1];
31     for (int i=cnt; i; i--) q[c[mx[i]]--]=i;
32     rep(i,1,cnt) res[i]=mx[i];
33 }
34 
35 void Go(int s[],int n){
36     int x=1,len=0;
37     rep(i,1,n){
38         int c=s[i];
39         if (son[x][c]) x=son[x][c],f[x]=max(f[x],++len);
40         else{
41             while (x && !son[x][c]) x=fa[x];
42             if (!x) x=1,len=0; else len=mx[x]+1,x=son[x][c],f[x]=max(f[x],len);
43         }
44     }
45     for (int i=cnt; i; i--){
46         int x=q[i]; res[x]=min(res[x],f[x]);
47         if (f[x] && fa[x]) f[fa[x]]=mx[fa[x]];
48         f[x]=0;
49     }
50 }
51 
52 int main(){
53     scanf("%d%d%d",&n,&len,&fir);
54     rep(i,1,len-1) scanf("%d",&x),s[i]=x-fir,fir=x;
55     len--; rep(i,1,len) ext(s[i]);
56     Radix();
57     rep(i,2,n){
58         scanf("%d%d",&len,&fir);
59         rep(i,1,len-1) scanf("%d",&x),s[i]=x-fir,fir=x;
60         len--; Go(s,len);
61     }
62     rep(i,2,cnt) ans=max(ans,res[i]);
63     printf("%d\n",ans+1);
64     return 0;
65 }

 

 

posted @ 2018-08-08 10:07  HocRiser  阅读(181)  评论(0编辑  收藏  举报