KMP/前綴出現次數統計(codeforces 432D)

題目鏈接
對於這個題,我們再利用KMP求出next數組後,可以有一下方法統計前綴字符出現的次數。

    for (int i = 0; i <= na; i++) cnt[i] = 1;
    for (int i = na; i >= 1; i--) cnt[nta[i]] += cnt[i];

第一個for,很好理解,就是前綴本身就算一個,那麼後一個for呢?
我們看樣例:

ABACABA

跑完兩個循環cnt數組:

4 2 2 1 1 1 1

我們手動模擬一下可知:
如果我們確定了第i個前綴cnt的值cnt[i]cnt[i],那麼該cnt[i]cnt[i]應該累加到所有可以與該前綴匹配的點上。
所以就有:

cnt[nta[i]] += cnt[i]

講起來比較繞,自己手動模擬一邊就懂的差不多了。
下面是ac代碼:

#include <iostream>
#include <cstring>
#define ll long long
using namespace std;
typedef unsigned ll ull;
const int N = 1e6+5;
char a[N];
int nta[N];
int cnt[N];
int ansl[N], ansn[N];
int tot;
int main()
{
    scanf("%s", a+1);
    int na = strlen(a+1);
    for (int i = 2, j = 0; i <= na; i++)
    {
        while(j > 0 && a[i] != a[j+1]) j = nta[j];
        if (a[i] == a[j+1]) j++;
            nta[i] = j;
    }
    for (int i = 0; i <= na; i++) cnt[i] = 1;
    for (int i = na; i >= 1; i--) cnt[nta[i]] += cnt[i];
    int gg = nta[na];
    for (; gg != 0; gg = nta[gg])
    {
        ansl[tot] = gg;
        tot++;
    }
    printf("%d\n", tot+1);
    for (int i = tot-1; i >= 0; i--)
    {
        printf("%d %d\n", ansl[i], cnt[ansl[i]]);
    }
    printf("%d %d\n", na, 1);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章