Period (KMP)

5 篇文章 0 订阅

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值