洛谷 P3435 [POI2006]OKR-Periods of Words
题目传送门
解题思路:
这道题题面比较乱,先说一下这道题要求什么:
对于一个字符串,求它及它的所有前缀的一个答案串的长度之和,答案串就是对于一个字符串,找到一个它的一个前缀,这个前缀后面在复制一遍,得到一个新串,这个新串包含原来那个字符串,而且这个前缀要求找符合要求的最长的.
这道题要求的答案串很显然就是整个字符串减去最短公共前后缀(不为0),若无公共前后缀,那么就无周期.
那么如何求最短公共前后缀呢?暴力的做法就是递归next[i],next[next[i]]...
而我们用记忆化,每找一个最短公共前后缀,就把next[i]更新,下次直接调用next[i]就找到答案了.
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 int n,kmp[1000001],j; 7 long long ans; 8 string l,p; 9 10 int main() { 11 scanf("%d",&n); 12 cin >> p; 13 l = " " + p; 14 kmp[1] = 0; 15 for(int i = 2;i <= n; i++) { 16 while(j != 0 && l[i] != l[j+1]) j = kmp[j]; 17 if(l[i] == l[j+1]) j++; 18 kmp[i] = j; 19 } 20 for(int i = 2,u = i;i <= n; i++,u = i) { 21 while(kmp[u]) u = kmp[u]; 22 if(kmp[i]) kmp[i] = u; 23 ans += i - u; 24 } 25 printf("%lld",ans); 26 return 0; 27 }