1468:OKR-Periods of Words(kmp算法)

【題目描述】
原題來自:POI 2006

串是有限個小寫字符的序列,特別的,一個空序列也可以是一個串。一個串 P 是串 A 的前綴,當且僅當存在串 B,使得 A=PB。如果P≠A並且 P 不是一個空串,那麼我們說 P 是 A 的一個 proper 前綴。

定義 Q 是 A 的週期,當且僅當 Q 是 A 的一個 proper 前綴並且 A 是 QQ 的前綴(不一定要是 proper 前綴)。比如串 abab 和 ababab 都是串 abababa 的週期。串 A 的最大週期就是它最長的一個週期或者是一個空串(當 A 沒有周期的時候),比如說,ababab 的最大週期是 abab。串 abc 的最大週期是空串。

給出一個串,求出它所有前綴的最大週期長度之和。

【輸入】
第一行一個整數 k,表示串的長度。

接下來一行表示給出的串。

【輸出】
輸出一個整數表示它所有前綴的最大週期長度之和。

【輸入樣例】
8
babababa
【輸出樣例】
24
思路:
看到這個題目描述就覺得這不是什麼人話。。。看了兩遍才懂它說的啥。其實就是:給你一個字符串t,找到它所有前綴字串的最長週期的長度的和。
週期是這樣定義的:對於一個字符串A,找到它的一個前綴子串s,如果ss的前綴是A,那麼s就是A的一個週期,如果A不是ss的前綴,那麼s就不是A的週期。
明白題意之後就開始想樣例,babababa,它的最長週期是什麼,很明顯是bababa。
接下來列舉樣例的每個前綴字串的最長週期:
b 0
ba 0
bab ba
baba ba
babab baba
bababa baba
bababab bababa
babababa bababa
可以注意到我們只要求出它的最短相同前後綴的長度就好了。比如bab的最短相同前後綴分別是b 和b。然後再用這個子串的長度減去這個最短相同前後綴的長度就可以了。
我們知道kmp算法中的next數組表示的意義是最長相同前後綴的長度。而這個題目中我們要求最短相同前後綴的長度,我們利用next數組,每次向前跳,當next[now]==0時停止,這裏相當於到了最短相同前後綴的位置了。然後再用當前串長度i減去now就是最長週期了。(如果沒有明白的話就手動模擬一下吧)
考慮到每次求最短相同前後綴的長度的過程存在重複計算的過程,是會超時的,所以我們需要對求解路徑進行一下壓縮(類似於並查集裏的那個路徑壓縮)每次找到最短相同前後綴時執行一次next[i]=now就行了
代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e6+10;
char a[N];
int p[N],n;
ll ans;
void pre()//預處理
{
    p[1]=0;
    int j=0;
    for(int i=1;i<n;i++)
    {
        while(j>0&&a[i+1]!=a[j+1]) j=p[j];
        if(a[i+1]==a[j+1]) j++;
        p[i+1]=j;
    }
}
void get_ans()
{
    int now;
    for(int i=1;i<=n;i++)
    {
        now=i;
        while(p[now]!=0) now=p[now];
        if(p[i]!=0) p[i]=now;
        ans+=i-now;
    }
}
int main()
{
    scanf("%d",&n);
    scanf("%s",a+1);
    pre();
    get_ans();
    printf("%lld\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章