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;
}
posted @ 2023-02-04 12:54  5k_sync_closer  阅读(3)  评论(0编辑  收藏  举报  来源