DZY Loves Strings
字符串?哈希!
考虑暴力,对每次询问 $a,b$ 找到其在 $S$ 中的所有出现,
对 $a$ 的所有出现,找到与其最近的 $b$ 的出现,
不难发现若 $a$ 的枚举是单调的,则 $b$ 的枚举也是单调的。
对 $a,b$ 的出现次数根号分治,注意到 $1\le|a|,|b|\le4$,则出现次数 $\Omega(\sqrt n)$ 的串有 $O(\sqrt n)$ 个。
对所有出现次数 $\Omega(\sqrt n)$ 的串,处理其与其他所有串($O(n)$ 个)的答案。
询问 $a,b$ 时,若其一出现次数 $\Omega(\sqrt n)$,查表即可。
若 $a,b$ 出现次数均为 $O(\sqrt n)$,则可以保证暴力复杂度为 $O(\sqrt n)$。
#include <vector>
#include <cstdio>
#include <cstring>
#define B 27ll
using namespace std;
vector<int> v[150050];
char s[50050];
int n, m, c1, c2, p1[600050], L[150050], p[5][50050], p2[150050], f[350][150050];
int H(int l, int r)
{
int q = 0;
for (int i = l; i <= r; ++i)
q = q * B + s[i] - 'a' + 1;
return q;
}
int main()
{
memset(f, 0x3f, sizeof f);
scanf("%s", s + 1);
n = strlen(s + 1);
for (int z = 1; z <= 4; ++z)
for (int l = 1, k; l + z - 1 <= n; ++l)
{
if (!p1[k = H(l, l + z - 1)])
L[p1[k] = ++c1] = z;
v[p[z][l] = p1[k]].push_back(l);
}
for (int i = 1; i <= c1; ++i)
if (v[i].size() >= 450)
{
p2[i] = ++c2;
for (int j = 1, x1, x2, y1, y2; j < v[i].size(); ++j)
{
x1 = v[i][j - 1];
x2 = x1 + L[i] - 1;
y1 = v[i][j];
y2 = y1 + L[i] - 1;
for (int z = 1; z <= 4; ++z)
for (int l = x1, r; l < y1 && l + z - 1 <= n; ++l)
r = l + z - 1, f[c2][p[z][l]] = min(f[c2][p[z][l]], min(max(r, x2) - x1 + 1, max(r, y2) - l + 1));
}
int x1 = v[i][0], x2 = x1 + L[i] - 1;
for (int z = 1; z <= 4; ++z)
for (int l = 1; l < x1; ++l)
f[c2][p[z][l]] = min(f[c2][p[z][l]], max(x2, l + z - 1) - l + 1);
x1 = v[i][v[i].size() - 1], x2 = x1 + L[i] - 1;
for (int z = 1; z <= 4; ++z)
for (int l = x1; l + z - 1 <= n; ++l)
f[c2][p[z][l]] = min(f[c2][p[z][l]], max(x2, l + z - 1) - x1 + 1);
}
scanf("%d", &m);
while (m--)
{
scanf("%s", s + 1);
int a = p1[H(1, strlen(s + 1))];
scanf("%s", s + 1);
int b = p1[H(1, strlen(s + 1))];
if (!a || !b)
puts("-1");
else if (p2[a])
printf("%d\n", f[p2[a]][b]);
else if (p2[b])
printf("%d\n", f[p2[b]][a]);
else
{
int u = 0, q = 1e9;
for (int i = 0, l1, r1, l2, r2; i < v[a].size(); ++i)
{
l1 = v[a][i];
r1 = l1 + L[a] - 1;
while (u + 1 < v[b].size() && v[b][u] < l1)
++u;
l2 = v[b][u];
r2 = l2 + L[b] - 1;
if (l2 >= l1)
{
q = min(q, max(r1, r2) - l1 + 1);
if (u)
{
l2 = v[b][u - 1];
r2 = l2 + L[b] - 1;
q = min(q, max(r1, r2) - l2 + 1);
}
}
else
q = min(q, max(r1, r2) - l2 + 1);
}
printf("%d\n", q);
}
}
return 0;
}