LA3026 Period [KMP]

2 篇文章 0 订阅

For each pre x of a given string S with Ncharacters (each character has an ASCII code between 97 and126, inclusive), we want to know whetherthe pre x is a periodic string. That is, for each i (2 i N)we want to know the largest K > 1 (ifthere is one) such that the pre x of S with length i can bewritten as AK, that is A concatenated K times, for somestring A. Of course, we also want to knowthe period K.

Input

The input  le consists of several test cases. Each testcase consists of two lines. The  rst onecontainsN (2 N 1000000) the size of the stringS. The second line contains the string S. The input  ends with a line, having the number zero onit.

Output

For each test case, output `Test case #'and the consecutive test case number on a single line; then, foreach pre x with length i that has a periodK > 1, output the pre x size i and the period K separated by a single space; the pre x sizes must bein 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

 

题意:对于给定的字符串的每一个前缀求其是否有循环节,若有,输出最小循环节;

分析:之金额道题可以运用nxt数组的性质,即每一个数字前面的最大的前缀后缀相同的长度来做,即可以把两条相同的链错开一部分,则那部分就是i-nxt[i],也就是循环节(为什么是循环节可以多摆几条就知道了),然后就是直接求nxt了;

这里要注意的是,这里的nxt数组要求到最后,也就是len,尽管这里没有字母,但nxt数组存的是前len个字母的自循环,所以这里也有可能。

然后就是,我写的方式和模板不太一样,比如说0的时候赋成-1要好操作一些(不用++),,比较的时候用i-1(因为是前i个字母的自我覆盖);个人觉得这么写更满足nxt数组的本来的意思。

在之前的hdu解题报告也加上了这么写的AC程序,可以参考一下;

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e6+5;
char tmp[maxn];
int n,nxt[maxn],len,lll;
int read()
{
scanf("%s",&tmp);len=strlen(tmp);
int bck=0;
for(int i=0;i<len;i++)bck=bck*10+tmp[i]-'0';
return bck;
}
int main()
{
freopen("LA3026.in","r",stdin);
freopen("LA3026.out","w",stdout);
for(n=read();n!=0;n=read()){
lll++;scanf("%s",&tmp);len=strlen(tmp);
printf("Test case #%d\n",lll);
nxt[0]=-1;nxt[1]=0;
for(int i=2;i<=len;i++){
int cnt=i-1;
while(tmp[nxt[cnt]]!=tmp[i-1]&&cnt)cnt=nxt[cnt];
nxt[i]=nxt[cnt]+1;
if(!(i%(i-nxt[i]))&&nxt[i])
printf("%d %d\n",i,i/(i-nxt[i]));
}
printf("\n");
}
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值