P5112 FZOUTSY 题解

$\operatorname{LCP}(a,b)\ge k\Leftrightarrow$ $\forall i\le k,a_i=b_i$。

维护出每个后缀 $s_i$ 长度为 $k$ 的前缀 $a_i$。

然后就是数区间 $a_i$ 相同对数,莫队维护。

$\sqrt{n^2m}=n\sqrt m\le\sqrt{10^{15}}$,可以过掉。

#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
struct Q{int l, r, i;}q[3000050];
int n, m, k, z, t[3000050], c[3000050];char f[3000050];
unsigned long long g = 1, a[3000050], v[3000050], h[3000050];long long p, s[3000050];
void I(int x) {p += c[a[x]]++;}void D(int x) {p -= --c[a[x]];}
bool B(Q x, Q y) {return t[x.l] == t[y.l] ? t[x.l] & 1 ? x.r < y.r : x.r > y.r : x.l < y.l;}
int main()
{
    scanf("%d%d%d%s", &n, &m, &k, f + 1);
    for(int i = 1;i <= k;++i) g *= 233;
    for(int i = 1, k = n / sqrt(m) + 1;i <= n;++i)
        h[i] = h[i - 1] * 233 + f[i], t[i] = (i - 1) / k + 1;
    for(int i = 1;i <= n - k + 1;++i) v[z++] = a[i] = h[i + k - 1] - h[i - 1] * g;
    sort(v, v + z);z = unique(v, v + z) - v;
    for(int i = 1;i <= n - k + 1;++i) a[i] = lower_bound(v, v + z, a[i]) - v + 1;
    for(int i = 0;i < m;++i)
        scanf("%d%d", &q[i].l, &q[i].r), q[i].r = min(q[i].r, n - k + 1),
        q[i].l = min(q[i].l, q[i].r + 1), q[i].i = i;
    sort(q, q + m, B);for(int i = 0, l = 1, r = 0;i < m;++i)
    {
        while(l > q[i].l) I(--l);while(r < q[i].r) I(++r);
        while(l < q[i].l) D(l++);while(r > q[i].r) D(r--);
        s[q[i].i] = p;
    }
    for(int i = 0;i < m;++i) printf("%lld\n", s[i]);return 0;
}
posted @ 2023-03-20 08:34  5k_sync_closer  阅读(1)  评论(0编辑  收藏  举报  来源