Sandy和Sue的热衷于收集干脆面中的卡片。然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积
攒卡片兑换超炫的人物模型。每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型
,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人
物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。Sandy的卡片数远
远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片
,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到
哪个等级的人物模型。
第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy现在有的卡片数
第i+1行到第i+N行每行第一个数为第i张卡片序列的长度Mi,之后j+1到j+1+Mi个数,用空格分隔,分别表示序列中
的第j个数
n<=1000,M<=1000,2<=Mi<=101
深夜写模板题...听起来不错...
把$n$个串连起来求一个后缀数组,然后二分答案$k$,判断是否存在一个连续的$height>=k$区间出现了$n$个串...
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=1000+5,maxm=1000+5,maxlen=2000000+5;
int n,m,Min,s[maxlen],id[maxlen],len[maxn],vis[maxn],str[maxn][maxm];
int sa[maxlen],gs[maxlen],wb[maxlen],wv[maxlen],ran[maxlen],height[maxlen];
inline bool cmp(int *x,int a,int b,int l){
return x[a]==x[b]&&x[a+l]==x[b+l];
}
inline void da(int *sa,int *x,int n,int m){
int i,j,p,*y=wb;
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[x[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
for(j=1,p=1;p<n;j<<=1,m=p){
for(i=n-j,p=0;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) gs[i]=0;
for(i=0;i<n;i++) gs[wv[i]]++;
for(i=1;i<m;i++) gs[i]+=gs[i-1];
for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
}
inline void calcheight(int n){
int i,j,k=0;
for(i=0;i<=n;i++) ran[sa[i]]=i;
for(i=0;i<n;height[ran[i++]]=k)
for(k?k--:233,j=sa[ran[i]-1];s[j+k]==s[i+k];k++);
}
inline bool check(int k){
int cnt=0;
for(int l=1,r;l<=n;l=r+1){
while(l<n&&height[l]<k) l++;
r=l;if(r==n&&height[r]<k) return false;
while(r<n&&height[r+1]>=k) r++;
if(r-l+2>=m){
memset(vis,0,sizeof(vis));cnt=0;
for(int i=l-1;i<=r;i++)
if(id[sa[i]]) cnt+=vis[id[sa[i]]]^1,vis[id[sa[i]]]=1;
if(cnt==m) return true;
}
}
return false;
}
signed main(void){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
scanf("%d",&m);Min=1000;
for(int i=1;i<=m;i++){
scanf("%d",&len[i]),Min=min(Min,len[i]);
for(int j=1;j<=len[i];j++)
scanf("%d",&str[i][j]);
}
n=0;
for(int i=1;i<=m;i++,ran[n]=s[n++]=2000+i)
for(int j=2;j<=len[i];j++)
id[n]=i,ran[n]=s[n++]=str[i][j]-str[i][j-1];
da(sa,ran,n+1,4000);calcheight(n);
int l=1,r=Min-1,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans+1);
return 0;
}