1. 程式人生 > >51Nod - 1304 :字符串的相似度 (裸的擴展KMP)

51Nod - 1304 :字符串的相似度 (裸的擴展KMP)

字母 前綴 scan length clas str input printf while

我們定義2個字符串的相似度等於兩個串的相同前綴的長度。例如 "abc" 同 "abd" 的相似度為2,"aaa" 同 "aaab" 的相似度為3。

給出一個字符串S,計算S同他所有後綴的相似度之和。例如:S = "ababaa",所有後綴為: ababaa 6 babaa 0 abaa 3 baa 0 aa 1 a 1 S同所有後綴的相似度的和 = 6 + 0 + 3 + 0 + 1 + 1 = 11

Input輸入一個字符串S(1 <= L <= 1000000),L為字符串S的長度,且S由a-z的小寫字母組成。Output輸出S同所有後綴的相似度的和。Sample Input

ababaa

Sample Output

11

: KMP可以求S串以i結尾的後綴與T串的前綴最長公共串長度。

: 擴展KMP可以求S串以i為起點的的後綴與T串的前綴的最長公共字串。

此題就是求所有i的擴展KMP長度;

以前學過,已經忘得差不多了。這裏再抄一發。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1001010;
int next[N],extand[N];
char
S[N]; long long ans; void getnext(){ int i,length=strlen(S+1); next[1]=length; for(i=0;i+1<length&&S[i+1]==S[i+2];i++); next[2]=i; int a=2; for(int k=3;k<=length;k++){ int p=a+next[a]-1, L=next[k-a+1]; if(L>=p-k+1){
int j=(p-k+1)>0?(p-k+1):0; while(k+j<=length&&S[k+j]==S[j+1]) j++; next[k]=j, a=k; } else next[k]=L; } for(int i=1;i<=length;i++) ans+=next[i]; printf("%lld\n",ans); } int main(){ scanf("%s",S+1); getnext(); return 0; }

51Nod - 1304 :字符串的相似度 (裸的擴展KMP)