UVAlive 3026 KMP 最小循环节

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 }

三: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 }

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

时间: 2024-08-14 15:10:41

UVAlive 3026 KMP 最小循环节的相关文章

HDU - 4333 Revolving Digits(拓展kmp+最小循环节)

1.给一个数字字符串s,可以把它的最后一个字符放到最前面变为另一个数字,直到又变为原来的s.求这个过程中比原来的数字小的.相等的.大的数字各有多少. 例如:字符串123,变换过程:123 -> 312 -> 231 -> 123 因为:312>123, 231>123, 123=123 所以答案是:0 1 2 2.令str1=s,str2=s+s,然后str1作为子串,str2作为主串,进行扩展kmp求出str2[i...len2-1]与str1[0...len1-1]的最长

hdu4333 Revolving Digits(扩展kmp+kmp最小循环节)

题目链接:点击打开链接 题意描述:给定一个字符串,可以把字符串的后x位移到字符串前面组成一个新的字符串?问对于所有的新组成的字符串中去掉重复的之后,比原串小的个数,等于的个数,大于的个数? 解题思路:扩展KMP(next1[i]数组含义:x[i···len-1]与x[0···len-1]的最长公共前缀) 分析:首先我们把字符串s复制一遍接到原字符串后面形成ss,这样在ss中以i(i>=0&&i<len)为起点的长度为len的字符串就是所有可能的新字符串: 讲到这里,问题转变为在

HDU 3746 Cyclic Nacklace (KMP最小循环节)

Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11264    Accepted Submission(s): 4821 Problem Description CC always becomes very depressed at the end of this month, he has check

【kmp+最小循环节】poj 2406 Power Strings

http://poj.org/problem?id=2406 [题意] 给定字符串s,s=a^n,a是s的子串,求n最大是多少 [思路] kmp中的next数组求最小循环节的应用 例如 ababab  next[6] = 4; 即 ababab ababab 1~4位  与2~6位是相同的 那么前两位 就等于3.4位 3.4位就等于5.6位 -- 所以 如果 能整除  也就循环到最后了 如果不能整除 就最后余下的几位不在循环内 例如 1212121 1212121 最后剩余1不能等于循环节 那么

【扩展kmp+最小循环节】HDU 4333 Revolving Digits

http://acm.hdu.edu.cn/showproblem.php?pid=4333 [题意] 给定一个数字<=10^100000,每次将该数的第一位放到放到最后一位,求所有组成的不同的数比原数小的个数,相等的个数,大的个数 [思路] 这个数很大,用字符串处理 比较两个字符串的大小,一位一位很耗时,可以求出最长公共前缀,只比较最长公共前缀后一位 每次将数的最后一位放到最后一位,如abcd变成dabc,cdab,bcda,相当于abcdabcd各个后缀的前四位 这样就变成了求abcdabc

Revolving Digits(扩展Kmp+最小循环节)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4333 Revolving Digits Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 28267    Accepted Submission(s): 6363 Problem Description One day Silence is

hdu 3746 Cyclic Nacklace (KMP求最小循环节)

//len-next[len]为最小循环节的长度 # include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int len; char a[100010]; int next[100010]; void Getnext() { int i=0,j=-1; next[0]=-1; while(i<=len) { if(j==-1||a[i]==a[j]) i

codeforces 825F F. String Compression dp+kmp找字符串的最小循环节

/** 题目:F. String Compression 链接:http://codeforces.com/problemset/problem/825/F 题意:压缩字符串后求最小长度. 思路: dp[i]表示前i个字符需要的最小次数. dp[i] = min(dp[j]+w(j+1,i)); (0<=j<i); [j+1,i]如果存在循环节(自身不算),那么取最小的循环节x.w = digit((i-j)/x)+x; 否则w = i-j+1; 求一个区间最小循环节: 证明:http://w

poj1961 Period kmp解决找字符串的最小循环节

/** 题目:poj1961 Period 链接:http://poj.org/problem?id=1961 题意:求从1到i这个前缀(2<=i<=N) ,如果有循环节(不能自身单独一个),输出前缀字符串长度以及最大的循环周期: 思路: 参考自:http://www.cnblogs.com/chenxiwenruo/p/3546457.html 定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0-len-next[len]-1]. (1)