[求所有循环节]Period II FZU1901

For each prefix with length P of a given string S,if

S[i]=S[i+P] for i in [0..SIZE(S)-p-1],

then the prefix is a “period” of S. We want to all the periodic prefixs.

Input

Input contains multiple cases.

The first line contains an integer T representing the number of cases. Then following T cases.

Each test case contains a string S (1 <= SIZE(S) <= 1000000),represents the title.S consists of lowercase ,uppercase letter.

Output

For each test case, first output one line containing "Case #x: y", where x is the case number (starting from 1) and y is the number of periodic prefixs.Then output the lengths of the periodic prefixs in ascending order.

Sample Input

4
ooo
acmacmacmacmacma
fzufzufzuf
stostootssto

Sample Output

Case #1: 3
1 2 3
Case #2: 6
3 6 9 12 15 16
Case #3: 4
3 6 9 10
Case #4: 2
9 12

题意: 求每个字符串的全部循环节。例如字符串fzufzufzuf的循环节有fzu,fzufzu,fzufzufzu,fzufzufzuf这四个。

分析: 首先有一个结论:每一个前后缀匹配都对应一个循环节,最长前后缀匹配next[len]对应最小循环节。可以用集合来粗略证明,任取一个前后缀匹配abaxxaba都存在对应的一个循环节abaxx,即前后缀匹配构成的集合包含于对应循环节的集合,同理,任取一个循环节,都存在对应的一个前后缀匹配,即循环节构成的集合包含于对应前后缀匹配的集合,因此两集合相等。有了这个结论后只需要求每个字符串所有的前后缀匹配即可。另外需要注意,循环节长度并不都是最小循环节整数倍 !如abaaaba这个字符串。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
//abaaab a
//abaa aba
//循环节长度并不都是最小循环节整数倍 
//每一个前后缀匹配都对应一个循环节
//最长前后缀匹配next[len]对应最小循环节
//因此求所有循环节只需要求出所有前后缀匹配 
int _next[1000005], st[1000005];
char s[1000005];

signed main()
{
	int T;
	cin >> T;
	for(int _ = 1; _ <= T; _++)
	{
		scanf("%s", s+1);
		int len = strlen(s+1);
		for(int i = 2, j = 0; i <= len; i++)
		{
			while(j && s[j+1] != s[i])
				j = _next[j];
			if(s[j+1] == s[i])
				j++;
			_next[i] = j;
		}
		int t = len, top = 0;
		while(t)
		{
			t = _next[t];
			st[++top] = len-t;
		}
		printf("Case #%d: %d\n", _, top);
		for(int i = 1; i <= top; i++)
			printf("%d ", st[i]);
		puts("");
	}
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值