1. 程式人生 > >[POI2006]OKR-Periods of Words

[POI2006]OKR-Periods of Words

cst rds www 發現 += %s 一個 字符 poi

Description

Luogu3435
對一個字符串\(A\),定義其周期\(Q\)為,\(Q\)\(A\)的前綴(\(Q!=A\))且\(A\)\(QQ\)的前綴(\(A\)可以等於\(QQ\))。求一個字符串的所有前綴的最長周期的長度之和。

Solution

首先觀察周期的定義,可以發現,一旦該字符串有一個前綴等於該字符串的一個後綴,那麽這個字符串就是有周期的,與前後綴有關的那就是KMP了。而要求周期最長,就是要求該前綴最短,轉化問題之後就可以用KMP解決了。但是,sb的我竟然在KMP的過程中xjb亂跳,直接就跳到最短的了,可是這樣會掛啊!考慮這樣的一個字符串abacabac,如果在KMP裏就處理答案的話就會影響next

數組的求解,所以要在KMP之後求答案。

哦對了,求答案的時候可以記憶化一下。

Code

#include <cstdio>

typedef long long LL;
const int N = 1e6 + 10;

char s[N];
int nxt[N]; 
LL ans;
int n;

int main() {
    scanf("%d", &n);
    scanf("%s", s+1);
    nxt[0] = -1;
    for (int i = 1; i <= n; ++i) {
        int t = nxt[i-1];
        while (t != -1 && s[t+1] != s[i]) t = nxt[t];
/*      這裏不能有這句話啊!!!!!!!!!!!!!!! 
        if (t != -1) while (nxt[t] != -1 && s[nxt[t] + 1] == s[i]) t = nxt[t];
*/      nxt[i] = t + 1;     
    }
    for (int i = 1; i <= n; ++i) {
        int t = nxt[i];
        while (nxt[t] > 0) t = nxt[t];
        if (nxt[i]) nxt[i] = t; // 記憶化一下 
        if (t) ans += i - t; 
    }
    printf("%lld\n", ans);
    return 0;
}

[POI2006]OKR-Periods of Words