CF710F String Set Queries 题解

字符串?哈希!

容易发现 $|s_i|$ 的长度有 $O(\sqrt{\sum|s_i|})$ 种。

匹配模板串 $S$ 时,考虑其所有长度为 $k|\exists s_i,|s_i|=k$ 的子串(而非所有子串) $T$($O(\sum|s_i|\sqrt{\sum|s_i|})$ 种),累计 $T$ 在集合中出现的次数。

注意此算法复杂度基于 $k$ 的种类数 $O(\sqrt{\sum|s_i|})$,而不是 $S$ 的子串长度种类数 $O(\sum|s_i|)$,达到优化目的。

#include <cstdio>
#include <cstring>
#include <unordered_map>
#define B 233ll
#define M 1000000007
using namespace std;
char s[300050];
long long b[300050];
int n, m, o, x, z, f[300050], d[300050], r[300050];
unordered_map<int, int> c[650];
int main()
{
    scanf("%d", &m);
    for (int i = b[0] = 1; i <= 300000; ++i)
        b[i] = b[i - 1] * B % M;
    while (m--)
    {
        scanf("%d%s", &o, s + 1);
        n = strlen(s + 1);
        for (int i = 1; i <= n; ++i)
            f[i] = (f[i - 1] * B + s[i]) % M;
        switch (o)
        {
        case 1:
            r[x = d[n] ? d[n] : d[n] = ++z] = n;
            ++c[x][f[n]];
            break;
        case 2:
            --c[d[n]][f[n]];
            break;
        case 3:
            x = 0;
            for (int p = 1; p <= z; ++p)
                for (int l = 1, k; l + r[p] - 1 <= n; ++l)
                    x += c[p].count(k = (f[l + r[p] - 1] + M - f[l - 1] * b[r[p]] % M) % M) ? c[p][k] : 0;
            printf("%d\n", x);
            fflush(stdout);
        }
    }
    return 0;
}
posted @ 2023-02-04 13:10  5k_sync_closer  阅读(3)  评论(0编辑  收藏  举报  来源