码迷,mamicode.com
首页 > 其他好文 > 详细

UVAlive 3026 KMP 最小循环节

时间:2018-07-31 15:34:13      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:open   https   str   pac   opened   amp   .com   tps   dex   

KMP算法:

一:next数组:next[i]就是前面长度为i的字符串前缀和后缀相等的最大长度,也即索引为i的字符失配时的前缀函数。

二:KMP模板

技术分享图片
 1 /*
 2 pku3461(Oulipo), hdu1711(Number Sequence)
 3 这个模板 字符串是从0开始的
 4 Next数组是从1开始的
 5 */
 6 #include <iostream>
 7 #include <cstring>
 8 using namespace std;
 9 
10 const int maxn = 1000002;
11 int _next[maxn];
12 char S[maxn], T[maxn];
13 int slen, tlen;
14 
15 void getNext()
16 {
17     int j, k;
18     j = 0; k = -1; _next[0] = -1;
19     while(j < tlen)
20         if(k == -1 || T[j] == T[k])
21             _next[++j] = ++k;
22         else
23             k = _next[k];
24 }
25 
26 /*
27 }
28 返回模式串T在主串S中首次出现的位置
29 返回的位置是从0开始的。
30 */
31 int KMP_Index()
32 {
33     int i = 0, j = 0;
34     getNext();
35 
36     while(i < slen && j < tlen)
37     {
38         if(j == -1 || S[i] == T[j])
39         {
40             i++; j++;
41         }
42         else
43             j = _next[j];
44     }
45     if(j == tlen)
46         return i - tlen;
47     else
48         return -1;
49 }
50 /*
51 返回模式串在主串S中出现的次数
52 */
53 int KMP_Count()
54 {
55     int ans = 0;
56     int i, j = 0;
57     if(slen == 1 && tlen == 1)
58     {
59         if(S[0] == T[0])
60             return 1;
61         else
62             return 0;
63     }
64     getNext();
65     for(i = 0; i < slen; i++)
66     {
67         while(j > 0 && S[i] != T[j])
68             j = _next[j];
69         if(S[i] == T[j])
70             j++;
71         if(j == tlen)
72         {
73             ans++;
74             j = _next[j];
75         }
76     }
77     return ans;
78 }
79 int main()
80 {
81 
82     int TT;
83     int i, cc;
84     cin>>TT;
85     while(TT--)
86     {
87         cin>>S>>T;
88         slen = strlen(S);
89         tlen = strlen(T);
90         cout<<"模式串T在主串S中首次出现的位置是: "<<KMP_Index()<<endl;
91         cout<<"模式串T在主串S中出现的次数为: "<<KMP_Count()<<endl;
92     }
93     return 0;
94 }
View Code

 

三:KMP最小循环节、循环周期:

定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0…len-next[len]-1]。

(1)如果len可以被len - next[len]整除,则表明字符串S可以完全由循环节循环组成,循环周期T=len/L。

(2)如果不能,说明还需要再添加几个字母才能补全。需要补的个数是循环个数L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。

学习博客 https://www.cnblogs.com/chenxiwenruo/p/3546457.html

      https://www.cnblogs.com/c-cloud/p/3224788.html

 

循环节例题

题目链接   https://vjudge.net/problem/UVALive-3026

解析  每个前缀的最小循环节  KMP跑一边判断能不能整除就可以了

AC代码

 1 #include <bits/stdc++.h>
 2 #define pb push_back
 3 #define mp make_pair
 4 #define F first
 5 #define S second
 6 #define all(a) (a).begin(), (a).end()
 7 #define fillchar(a, x) memset(a, x, sizeof(a))
 8 #define huan printf("\n");
 9 using namespace std;
10 typedef long long ll;
11 const int maxn=1e6+10,inf=0x3f3f3f3f;
12 const ll mod=1e9+7;
13 char p[maxn];
14 int f[maxn];
15 int main()
16 {
17     int n,kase=0;
18     while(scanf("%d",&n)==1&&n)
19     {
20         scanf("%s",p);
21         f[0]=0,f[1]=0;
22         for(int i=1;i<n;i++)
23         {
24             int j=f[i];
25             while(j&&p[i]!=p[j]) j=f[j];
26             f[i+1]=(p[i]==p[j]?j+1:0);
27         }
28         printf("Test case #%d\n", ++kase);
29         for(int i=2;i<=n;i++)
30         {
31             if(f[i]>0&&i%(i-f[i])==0)
32                 printf("%d %d\n",i,i/(i-f[i]));
33         }
34         huan;
35     }
36 }

 

UVAlive 3026 KMP 最小循环节

标签:open   https   str   pac   opened   amp   .com   tps   dex   

原文地址:https://www.cnblogs.com/stranger-/p/9395397.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!