Period
题目链接
For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as AK ,that is A concatenated K times, for some string A. Of course, we also want to know the period K.
给定一个字符串,ascii码在97到126之间(字母)如果前i个字符组成的字符串是由子字符串循环一定次数组成的,则该字符串为周期串,子字符串为循环节。 比如aabaabaabaab,在前两个字符中a出现了两次,循环节为a。在前6个字符中,循环节出现了2次,循环节为aab,在前9个字符中,循环节出现了3次,循环节为aab;在12个字符中循环节出现了4次,循环节为aab。请编程写出给定字符串的n长度的周期串以及循环节出现的次数
Input
The input consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S.The second line contains the string S. The input file ends with a line, having the number zero on it.
第一行是一个整数 T ( 0<T<=100 ) 代表测试数据的组数。
之后T行每行一个字符串,由小写字母组成,字符串的长度3<=L<=100000。
Output
For each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.
每组数据输出一行结果。
Sample Input
3
aaa
12
aabaabaabaab
0
Sample Output
Test case #1
2 2
3 3
Test case #2
2 2
6 2
9 3
12 4
题目分析
每组给出一个长度为 n 的字符串,要求输出这个字符串每个前缀的最短循环节,简单来说,对于这个字符串的第 i 个前缀 ,求一个最大的整数,使得这个前缀是由某个字符串重复 k 次得到的,输出所有存在这个 k 值的 i 与对应的 k
此题用到最小循环节的定义,加一个挨个判断最小循环节的过程
最小循环节长度=字符串长度-Next[字符串长度]
cnt=len-Next[len]
aaa 的Next数组为 -1 0 1 2
最小循环节
代码实现
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<math.h>
using namespace std;
typedef long long int ll;
char a[1000005];
int Next[1000005];
int len;
void getnext(char *a)
{
int i,j;
i=0,j=-1;
Next[0]=-1;
while(i<len)
{
if(j==-1||a[i]==a[j])
{
Next[++i]=++j;
}
else
j=Next[j];
}
}
int main()
{
int t,Case=0;
while(cin>>t&&t)
{
scanf("%s",a);
len=strlen(a);
getnext(a);
printf("Test case #%d\n",++Case);
for(int i=1;i<=t;i++)
{
int cnt=i-Next[i];
if(Next[i]>0&&i%cnt==0)
//Next[i]>0就表示出现重复字符Next[i]==0的话就是出现新的字符
printf("%d %d\n",i,i/cnt);//输出所在位置和循环次数
}
cout<<endl;
}
return 0;
}