Solution
容易看出“相同”指差分后相同的+1
将所有串差分后得到的串(长度-1)放在一起,两个串间以一个串内未出现且各不相同的数相隔,记录每个数原属的串
后缀数组求height
二分查找最大的数,使有 n 个属于不同原串的点满足height>=这个数
Code
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; const int N=1001,M=102,K=N*M; int gs,n,m,b[K],a[N][M],len[N],ma,mi,l,r,inf=1<<30,id[K],ans; int rk1[K],rk2[K],rk[K],pre[K],sa[K],cnt[K],he[K]; void init() { scanf("%d",&gs); mi=r=inf; for(int i=1;i<=gs;i++) { scanf("%d",&len[i]); for(int j=1;j<=len[i];j++) { scanf("%d",&a[i][j]); if(j>1) ma=max(ma,a[i][j]-a[i][j-1]); } r=min(r,len[i]-1); } for(int i=1;i<=gs;b[++n]=++ma,i++) for(int j=2;j<=len[i];j++) { b[++n]=a[i][j]-a[i][j-1]; id[n]=i; mi=min(mi,b[n]); } for(int i=1;i<=n;i++) b[i]-=mi-1,m=max(m,b[i]); } void get_sa() { for(int i=1;i<=n;i++) cnt[b[i]]++; for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(int i=1;i<=n;i++) rk[i]=cnt[b[i]-1]+1; for(int mid=1;mid<n;mid<<=1) { for(int i=1;i<=n;i++) { rk1[i]=rk[i]; if(i+mid<=n) rk2[i]=rk[i+mid]; else rk2[i]=0; } memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++) cnt[rk2[i]]++; for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1]; for(int i=n;i;i--) pre[cnt[rk2[i]]--]=i; memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++) cnt[rk1[i]]++; for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1]; for(int i=n;i;i--) sa[cnt[rk1[pre[i]]]--]=pre[i]; rk[sa[1]]=1; for(int i=2;i<=n;i++) if(rk1[sa[i]]==rk1[sa[i-1]] && rk2[sa[i]]==rk2[sa[i-1]]) rk[sa[i]]=rk[sa[i-1]]; else rk[sa[i]]=rk[sa[i-1]]+1; if(rk[sa[n]]==n) return ; } } void get_he() { int k=0; for(int i=1;i<=n;i++) { if(rk[i]==1) continue; if(k) k--; int j=sa[rk[i]-1]; while(i+k<=n && j+k<=n && b[i+k]==b[j+k]) k++; he[rk[i]]=k; } } int st[K],vis[K],top; bool check(int x) { while(top) vis[st[top--]]=0; for (int i=1;i<=n;i++) { if(he[i]<x) while (top) vis[st[top--]]=0; if(!vis[id[sa[i]]]) { vis[id[sa[i]]]=1; st[++top]=id[sa[i]]; if(top==gs) return 1; } } return 0; } int main() { init(); get_sa(); get_he(); while(l<=r) { int mid=(l+r)>>1; if(check(mid)) l=mid+1,ans=mid; else r=mid-1; } printf("%d",ans+1); return 0; }