这题数据范围贼小……听说可以用各种乱七八糟的暴力随便过去。
其实这题就是找最长公共子串。但是我一直不知道怎么处理加数的情况……今天豁然开朗,直接对每个串做一次差分就好了。
之后就是我们正常的匹配,每次用子树内的值更新节点的值,最后的时候答案取所有节点最小匹配值的最大值+1.
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('
')
using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 2000005;
const ll INF = 5e18;
int read()
{
int ans = 0,op = 1;char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
return ans * op;
}
int n,ans,maxn[M],minn[M],a[M],c[M],b[M];
struct Suffix
{
map <int,int> ch[M];
int last,cnt,fa[M],l[M];
void extend(int c)
{
int p = last,np = ++cnt;
l[np] = l[p] + 1,last = cnt;
while(p && !ch[p].count(c)) ch[p][c] = np,p = fa[p];
if(!p) {fa[np] = 1;return;}
int q = ch[p][c];
if(l[q] == l[p] + 1) fa[np] = q;
else
{
int nq = ++cnt;
l[nq] = l[p] + 1,ch[nq] = ch[q];
fa[nq] = fa[q],fa[np] = fa[q] = nq;
while(ch[p][c] == q) ch[p][c] = nq,p = fa[p];
}
}
void cal()
{
rep(i,1,cnt) c[l[i]]++;
rep(i,1,cnt) c[i] += c[i-1];
rep(i,1,cnt) a[c[l[i]]--] = i;
}
void match(int *b,int k)
{
int u = 1,len = 0;
rep(i,2,k)
{
int f = b[i] - b[i-1];
while(u != 1 && !ch[u][f]) u = fa[u],len = l[u];
if(ch[u][f]) len++,u = ch[u][f],maxn[u] = max(maxn[u],len);
}
per(i,cnt,1)
{
int p = a[i];
maxn[fa[p]] = max(maxn[fa[p]],min(maxn[p],l[fa[p]]));
minn[p] = min(minn[p],maxn[p]),maxn[p] = 0;
}
}
}SAM;
int main()
{
n = read(),SAM.cnt = SAM.last = 1;
memset(minn,0x3f,sizeof(minn));
int k = read();
rep(i,1,k) {b[i] = read(); if(i >= 2) SAM.extend(b[i] - b[i-1]);}
SAM.cal();
rep(i,2,n)
{
int k = read();
rep(i,1,k) b[i] = read();
SAM.match(b,k);
}
rep(i,1,SAM.cnt) ans = max(ans,minn[i]+1);
printf("%d
",ans);
return 0;
}