题目链接
- 在变化中寻找不变的量
- 通过差分转化为字符串匹配问题
- 通过打标记区分来自同一个字符串的不同子串
- 二分答案转化为判定
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int m[1005],a[105],c[105],s[200005],ha[1005];
int rk[20][200005],r[200005],sa[200005],h[200005],w,p[25],id[200005];
struct t1
{
int v,id;
}t[200005];
bool cmp1(t1 a,t1 b)
{
return a.v<b.v;
}
bool cmp2(int a,int b)
{
if(rk[w-1][a]!=rk[w-1][b])
{
return rk[w-1][a]<rk[w-1][b];
}
return rk[w-1][min(a+p[w-1],200001)]<rk[w-1][min(b+p[w-1],200001)];
}
queue<int>q;
int main()
{
int L=0,R=2000;
p[0]=1;
for(int i=1;i<=20;i++)
{
p[i]=p[i-1]*2;
}
int n;
cin>>n;
int tot=0;
for(int i=1;i<=n;i++)
{
m[i]=read1();
R=min(R,m[i]);
for(int j=1;j<=m[i];j++)
{
a[j]=read1();
c[j-1]=a[j]-a[j-1];
}
int j=1;
while(j<m[i])
{
tot++;
s[tot]=c[j];
id[tot]=i;
j++;
}
tot++;
s[tot]=3000;
id[tot]=0;
}
for(int i=1;i<=tot;i++)
{
t[i].id=i;
t[i].v=s[i];
sa[i]=i;
}
sort(t+1,t+tot+1,cmp1);
t[0].v=2000;
int cnt=0;
for(int i=1;i<=tot;i++)
{
if(t[i].v!=t[i-1].v)
{
cnt++;
}
rk[0][t[i].id]=cnt;
}
for(int i=1;i<=18;i++)
{
w=i;
sort(sa+1,sa+tot+1,cmp2);
cnt=0;
for(int j=1;j<=tot;j++)
{
if(rk[w-1][sa[j]]!=rk[w-1][sa[j-1]]||rk[w-1][min(sa[j]+p[w-1],200001)]!=rk[w-1][min(sa[j-1]+p[w-1],200001)])
{
cnt++;
}
rk[w][sa[j]]=cnt;
}
}
for(int i=1;i<=tot;i++)
{
r[i]=rk[18][i];
}
int k=0;
for(int i=1;i<=tot;i++)
{
if(r[i]==1)
{
h[r[i]]=0;
k=0;
continue;
}
while(i+k<=tot&&sa[r[i]-1]+k<=tot&&s[i+k]==s[sa[r[i]-1]+k])
{
k++;
}
h[r[i]]=k;
if(k) k--;
}
R--;
while(L<R)
{
int mid=(L+R+1)>>1;
while(!q.empty())
{
ha[q.front()]--;
q.pop();
}
bool f=false;
int sum=0;
for(int i=1;i<=tot;i++)
{
if(h[i]>=mid)
{
if(q.empty())
{
q.push(id[sa[i-1]]);
ha[id[sa[i-1]]]++;
if(id[sa[i-1]]!=0) sum++;
}
q.push(id[sa[i]]);
ha[id[sa[i]]]++;
if(ha[id[sa[i]]]==1&&id[sa[i]]!=0)
{
sum++;
if(sum==n)
{
f=true;
break;
}
}
}
else
{
while(!q.empty())
{
ha[q.front()]--;
q.pop();
}
sum=0;
}
}
if(f==true)
{
L=mid;
}
else
{
R=mid-1;
}
}
cout<<L+1<<endl;
return 0;
}
/*
5
5 1 2 3 7 9
3 1 5 7
5 9 2 6 8 0
6 1 1 1 3 7 9
6 0 4 2 0 4 6
*/