题面
解法
KMP大法吼啊
后缀数组当然也能做,待更
- 根据题意,两个字符串相等当且仅当长度相同并且一个字符串中所有数+ =另一个串中对应的数
- 那么,我们可以发现,这两个串相同一定满足这两个串的差分数组相同
- 所以,我们可以将原来的 个字符串变成 个长度为原来长度-1的新字符串
- 现在,问题就转化成要求这 个串的最长公共子串
- 不妨枚举第一个串的起点,将它对应的一段后缀和其他所有字符串做一遍匹配,最后匹配下来的最小值就是最长公共子串的长度
- 直接用KMP算法加速这个过程即可,代码简单易懂
- 时间复杂度:
代码
#include <bits/stdc++.h>
#define N 1010
#define M 110
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
int len, c[M], nxt[M], l[N], a[N][M], b[N][M];
void getnxt(int len) {
memset(nxt, 0, sizeof(nxt));
for (int i = 2; i <= len; i++) {
int j = nxt[i - 1];
while (j && c[i] != c[j + 1]) j = nxt[j];
if (c[i] == c[j + 1]) j++; nxt[i] = j;
}
}
int calc(int num) {
int L = l[num], ret = 0, j = 0;
for (int i = 1; i <= L; i++) {
while (j && a[num][i] != c[j + 1]) j = nxt[j];
if (a[num][i] == c[j + 1]) j++; chkmax(ret, j);
}
return ret;
}
int main() {
int n; read(n);
for (int i = 1; i <= n; i++) {
read(l[i]);
for (int j = 1; j <= l[i]; j++) read(b[i][j]); l[i]--;
for (int j = 1; j <= l[i]; j++) a[i][j] = b[i][j + 1] - b[i][j];
}
int ret = 0;
for (int j = 1; j <= l[1]; j++) {
len = l[1] - j + 1;
for (int i = 1; i <= len; i++) c[i] = a[1][i + j - 1];
getnxt(len); int ans = len;
for (int i = 2; i <= n; i++)
chkmin(ans, calc(i));
chkmax(ret, ans + 1);
}
cout << ret << "\n";
return 0;
}