【CH1809】匹配統計(KMP)

題目鏈接
摘自https://www.cnblogs.com/wyboooo/p/9829517.html

用KMP先求出以a[i]爲結尾的前綴與b匹配的最長長度。
比如 f[i]  = j,就表示a[1~i]的後綴最多可以和b[1~j]匹配。但求出這個並不意味着以a[i]爲開頭的後綴可以和b恰好匹配j位(因爲也許後面還可以匹配),但是可以肯定的是他至少可以匹配j位。我們很難求出恰好可以匹配x位的位置有多少,但是我們可以存至少可以匹配x位的位置的數目,結果用cnt[x] - cnt[x +1]就可以了。
因此cnt[f[i]] ++就很顯然了。
由於我們之前求出的是最長長度,因此當a[1~i]可以最多和b[1~j]匹配時,也一定存在一個小於j的k使得a[1~i]和b[1~k]匹配,也就是一定能找到一個位置,至少匹配k位,但這個可能我們在之前沒有加上過。而這個k恰好就等於nxt[j]。

xjc大佬還提出了一個hash+二分的做法,也能AC。
就是用二分長度+hash check求出每個位置的答案,然後直接用桶記錄秒出答案。
時間複雜度\(O(n\log n)\)

#include <cstdio>
#include <cstring>
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
const int MAXN = 200010;
int nxt[MAXN], n, m, q, f[MAXN], c[MAXN], d;
char a[MAXN], b[MAXN];
int main(){
    Open("str");
    scanf("%d%d%d%s%s", &n, &m, &q, a + 1, b + 1);
    int j = 0;
    for(int i = 2; i <= m; ++i){
        while(j && b[i] != b[j + 1]) j = nxt[j];
        if(b[j + 1] == b[i]) ++j;
        nxt[i] = j;
    }
    j = 0;
    for(int i = 1; i <= n; ++i){
        while(j && (a[i] != b[j + 1] || j == m)) j = nxt[j];
        if(a[i] == b[j + 1]) ++j;
        f[i] = j;
    }
    for(int i = 1; i <= n; ++i)
        ++c[f[i]];
    for(int i = m; i; --i)
        c[nxt[i]] += c[i];
    for(int i = 1; i <= q; ++i){
        scanf("%d", &d);
        printf("%d\n", c[d] - c[d + 1]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章