hdu 1358 Period (KMP-----next数组)

        Period
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
 use MathJax to parse formulas

Description

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 A  K , that is A concatenated K times, for some string A. Of course, we also want to know the period K. 
 

Input

The input file 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. 
 

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

给你一个串,让你求出这个串循环的次数和地方

比如说Case 2的aabaabaabaab

在第2个位置a循环了2次            输出2 2

在第6个位置aab循环了2次        输出6 2

在第9个位置aab循环了3次        输出9 3


这个题其实就是求next数组外加找规律


先来看下这张图


其中,蓝色的为i位置前,前缀和后缀相同的部分,橙色为二者相交的部分

下面开始推导:

            对于abcabc类串(只循环2次)

                        由于只循环2次,所以当i指向串的末尾的时候,next[i] = strlen(str)/2        (串的一半,正好前缀和后缀相等)

           

            对于多次循环的串(如同aaaaaaaa,其中a循环了N次):

                        则一定能满足上图.    因为是多次循环,所以前缀或者后缀与整个串的差别只有用来循环的那个串

                        比如说aaaa,a循环了4次,i=4的时候前缀为aaa,后缀为aaa,与原始串aaaa只差了一个用来循环的a


综上,我们一定有当字符串开始第二个周期的时候,总串长减去蓝色的长度就为循环节的长度

换成公式就是:

                记buf =    i-next[i](这一步是求相同部分,因为必定以这个数字循环的串的长度)

                if i%buf == 0  &&  i/buf > 1

                        则 i 为循环的一个位置,最短的循环的串的长度为buf,循环次数为i/buf(必须满足循环次数>=2)


式子有了代码就好写了

代码如下:

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cstring>
#define For(i,n) for(int i=0;i<n;i++)
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
const int maxn = 1e6+5;
int x;
char s2[maxn];
int nexta[maxn];
void Find_Next(){
    nexta[0] = -1;
    nexta[1] = 0;
    int cnt = 0;
    int i = 2;
    while(i<=x){
        if(s2[i-1]==s2[cnt])
            nexta[i++] = ++ cnt;
        else if(cnt>0)
            cnt = nexta[cnt];
        else
            nexta[i++] = 0;
    }
}


/*转载请保留此信息*/
/*hdu 1358 Period */
/*来源:   风灯记  */
/*https://blog.csdn.net/bestsort*/
int main() {
    int cnt = 0;
    while(cin >> x && x){
        cnt ++;
        mem(s2);
        mem(nexta);
        cin >> s2;

        Find_Next();
        cout << "Test case #" << cnt << endl;
        For(i,x+1){
            int buf = i-nexta[i];
            if(i%buf==0 && i/buf > 1)
                cout <<i << " " << i/buf << endl;
        }
        cout << endl;
    }
    return 0;
    }


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值