HDU-3746
现在给你一个字符串,请问在该字符串末尾最少添加多少个字符,可以让这个字符串获得重复循环序列。
输入:第一行是一个整数 T ( 0 < T < = 100 ) T ( 0<T<=100 ) T(0<T<=100) 代表测试数据的组数。之后 T T T行每行一个字符串,由小写字母组成,字符串的长度 3 < = L < = 100000 3<=L<=100000 3<=L<=100000。
输出:每组数据输出一行结果。
样例:
3
ppp
pip
machinelearning
0
1
15
思路:
循环节是指一段数据中重复的最小环。KMP不止要学会套模板匹配字符串,还要学到KMP算法的精髓——Next数组。
(未经优化的)
N
e
x
t
[
i
]
Next[i]
Next[i]指的
S
[
0
:
i
−
1
]
S[0:i-1]
S[0:i−1]的最大共同前后缀长度(例如abcabcabc的共同前后缀为abcabc, abcabc为abc, abcabcabcabc为abc*3)
故一段字符串的循环节就是:
N
−
N
e
x
t
[
N
]
N - Next[N]
N−Next[N]
将其记为len。若该字符串是循环字符串,则
N
%
l
e
n
=
=
0
N\%len==0
N%len==0, 而循环节的个数为:
N
/
l
e
n
N/len
N/len
若不是,则
N
e
x
t
[
N
]
=
=
0
Next[N] == 0
Next[N]==0(abcd)或者
N
%
l
e
n
!
=
0
N\%len\ !=\ 0
N%len != 0
题解:
#include<bits/stdc++.h>
#define maxn 1000005
using namespace std;
int n;
char s[maxn];
int Next[maxm];
int getnext()
{
Next[0] = -1;
int i = 0, j = -1;
while(i<n)
{
while(j!=-1 && s[i]!=s[j]) j = Next[j];
Next[++i] = ++j;
}
int len = - Next[n] + n;
if(Next[n]==0) return len; //没有循环部分,只能自身成为循环节
else if(Next[n]%len==0) return 0; //已经是循环字符串
else return len - Next[n] % len; //需要补齐
}
int main()
{
int T;
cin >> T;
getchar();
while(T--)
{
scanf("%s", s);
n = strlen(s);
cout << getnext() << endl;
}
return 0;
}
HDU-1385
给出一个字符串s(1为起始),问在[1, i]区间是否有完整的循环节,若有,输出i并输出循环次数
3
aaa
12
aabaabaabaab
0
Test case #1
2 2
3 3
Test case #2
2 2 --aa(a)
6 2 --aabaab(aab)
9 3 --aabaabaab(aab)
12 4 --....
思路:求出Next数组后从1开始遍历,若 S [ 1 − i ] S[1-i] S[1−i]是循环字符串则输出 i i i 和 N / l e n N / len N/len
题解:
#include<bits/stdc++.h>
#define maxn 1000005
using namespace std;
int N, kase=0;
char s[maxn];
int Next[maxn];
void getnext()
{
Next[0] = -1;
int i = 0, j = -1;
while(i<N)
{
while(j!=-1 && s[i]!=s[j]) j = Next[j];
Next[++i] = ++j;
}
printf("Test case #%d\n", ++kase);
for(int i=2;i<=N;i++)
{
if(Next[i]==0) continue;
int len = i - Next[i];
if(Next[i]%len==0) cout << i << ' ' << Next[i]/len+1 << endl;
}
putchar('\n');
}
int main()
{
scanf("%d", &N); getchar();
while(N)
{
gets(s);
getnext();
scanf("%d", &N); getchar();
}
return 0;
}
HUST-1010
对于字符串A, 将其重复多次,形成新的字符串AAA…AAAA,在其中截取一段,作为B.
现给定B字符串,求符合条件的最短的A
bcabcab
efgabcdefgabcde
3
7
思路:本题实际上就是在求B中的循环节长度,只不过前/后可以多/少一些部分,原来的方法依然是可求的。
代码略