拓展kmp的应用

Smiling & Weeping

                ---- 我与月亮,进行了一次深夜谈话

                  它与我谈论太阳,而我与它谈论你。

 

题目链接:P3435 [POI2006] OKR-Periods of Words - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:其实也就是kmp拓展,求s与s的每个后缀的LCP(最长公共前缀),但是这样超时,需要一个小小的优化(记录跳转即step[k],跳到可以上一个可以实现的地方,尽量保持复杂度在线性),同时s[i] == s[0]时,直接使ans += i;

Talk is cheap , show me the code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n , Next[1000100] , step[1000100];
 4 char str[1000100];
 5 void getNext(char *c){
 6     int len = strlen(c);
 7     int p = 0 , k = 1 , l;
 8     Next[0] = len;
 9     while(p+1 < len && c[p] == c[p+1]) p++;
10     Next[1] = p;
11     for(int i = 2; i < len; i++){
12         p = k+Next[k]-1;
13         l = Next[i-k];
14         if(i+l <= p) Next[i] = l;
15         else{
16             int j = max(0 , p-i+1);
17             while(i+j < len && c[i+j] == c[j]) j++;
18             Next[i] = j;
19             k = i;
20         }
21     } 
22 }
23 int main()
24 {
25     long long ans = 0;
26     int q=0 , k;                      // q代表周期,k代表最远到达的距离
27     scanf("%d",&n); scanf("%s",str);
28     getNext(str);
29     for(int i = 1; i < n; i++){
30         if(str[i] == str[0]){
31             ans += i;
32         } else {
33             int r = i-1 , tem = r;
34             while(Next[r] < i-r+1 && r >= (i+1)/2){
35                 if(step[r] && step[r] < r) // 警惕bug,可能有step[r]==r,陷入死循环
36                     r = step[r];
37                 else r--;
38             }
39             if(r >= (i+1)/2 && Next[r] >= i-r+1) ans += r;
40             step[tem] = r;
41         }
42     }
43     printf("%lld\n",ans);
44     return 0;
45 }

一棵树,一块岩石,一朵云

文章到此结束,我们下次再见

posted @ 2023-09-07 23:11  smiling&weeping  阅读(7)  评论(0)    收藏  举报