OKR-Periods of Words
傳送門:鏈接 來源:UPC 8180
題目描述
串是有限個小寫字符的序列,特別的,一個空序列也可以是一個串。一個串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
提示
對於全部數據,1<k<106
思路:
kmp算法中的Next[i]代表的是最大前後綴,即位置i的前後綴最大的相同長度爲Next[i](若Next[0]=-1,長度即爲Next[i]+1)。
這個題要求的是最小相同的前後綴(滿足題目中週期的定義),可能不太好理解,看下圖:(Next[0]=-1)
對應Next值:
求法:先正常求出Next數組,對每個Next[i]回溯到第一個不爲-1的位置,並賦值給Next[i]。
例如當i=5時,Next[5]=Next[Next[5]]=1,其餘同理。
AC代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MAX=1e6;
LL Next[MAX+5];
void getNext(string p,LL lp,LL Next[])
{
LL k=-1;
Next[0]=-1;
for(LL i=1;i<lp;i++){
while(k>-1&&p[k+1]!=p[i]) k=Next[k];
if(p[k+1]==p[i]) k++;
Next[i]=k;
}
}
int main()
{
LL lp;
string p;
cin>>lp>>p;
getNext(p,lp,Next);
for(LL i=0;i<lp;i++){
if(Next[i]==-1) continue;
else{
while(Next[Next[i]]!=-1){
Next[i]=Next[Next[i]];
}
}
}
LL sum=0;
for(LL i=0;i<lp;i++){
if(Next[i]!=-1)
sum+=(i-Next[i]);
}
cout<<sum<<endl;
return 0;
}