• POJ 1961 字符串 KMP (i-next[i])


    Period
    Time Limit: 3000MS   Memory Limit: 30000K
    Total Submissions: 16431   Accepted: 7886

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

    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.

    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 2http://write.blog.csdn.net/postedit?ref=toolbar
    3 3
    
    Test case #2
    2 2
    6 2
    9 3
    12 4


    此题为2406的升级版,重在理解KMP中next[i]和i-next[i]的用法,(2406为len-next[len]),next[i]即为到下标+1为止,是否与原串的从头开始有没有相同的子串,如果无,则为0,i-len[i]则为从0开始到i的匹配的相同子串的长度,换成len后,则为最长的那个。

    大意:
       定义字符串A,若A最多由n个相同字串s连接而成,则A=s^n,如"aaa" = "a"^3,"abab" = "ab"^2
       "ababa" = "ababa"^1
       
    给出一个字符串A,求该字符串的所有前缀中有多少个前缀SA= s^n(n>1)
    输出符合条件的前缀长度及其对应的n

      如aaa
      前缀aa的长度为2,由2个'a'组成
      前缀aaa的长度为3,由3个"a"组成




      分析:KMP
      若某一长度L的前缀符合上诉条件,则
        1.next[L]!=0(next[L]=0时字串为原串,不符合条件)
        2.L%(L-next[L])==0(此时字串的长度为L/next[L])


     对于2:有str[0]....str[next[L]-1]=str[L-next[L]-1]...str[L-1]
            =》str[L-next[L]-1] = str[L-next[L]-1+L-next[L]-1] = str[2*(L-next[L]-1)];
            假设S = L-next[L]-1;则有str[0]=str[s]=str[2*s]=str[3*s]...str[k*s],对于所有i%s==0,均有s[i]=s[0]
            同理,str[1]=str[s+1]=str[2*s+1]....
                  str[j]=str[s+j]=str[2*s+j]....
            综上,若L%S==0,则可得L为str[0]...str[s-1]的相同字串组成,
            总长度为L,其中字串长度SL = s-0+1=L-next[L],循环次数为L/SL
            故对于所有大于1的前缀,只要其符合上述条件,即为答案之一

    #include<iostream>
    using namespace std;
    const int Max = 1000005;
    
     
    
    char str[Max];
    int len, next[Max];
    
     
    
    void get_next(){
        int i = 0, j = -1;
        next[0] = -1;
        while(i < len){
            if(j == -1 || str[i] == str[j]){
                i ++; j ++;
                next[i] = j;
            }
            else j = next[j];
        }
    }
    
     
    
    int main(){
        int i, testCase = 1;
        while(scanf("%d", &len) && len){
            scanf("%s", str);
            get_next();
            printf("Test case #%d
    ", testCase ++);
            for(i = 2; i <= len; i ++)
                if(next[i] != 0 && i % (i-next[i]) == 0)
                    printf("%d %d
    ", i, i / (i-next[i]));
            printf("
    ");
        }
        return 0;
    }


    自己用的是2406的len-next[len],也就是分为了两种情况,不知道为什么WA,可有有什么特殊数据?

    附上自己WA的代码:

    #include<iostream>
    #include<cstring>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int Max = 100000005;
    
    char str[Max];       //  模式串。
    int len, next[Max];
    
    void get_next(){
        int i = 0, j= -1;
        next[0] =-1;
        while(i< len){
           if(j == -1 || str[i] == str[j]){
               ++i; ++j;
    
               next[i] = j;
           }
           else j = next[j];
        }
    }
    
    int main(){
    
       while(scanf("%d", &len) != EOF&&len!=0){
           scanf("%s",str);
           int cases = 1;
           int q=0;
           int k1 = 0,k2 = 0,ans=0;
           printf("Test case #%d
    ",cases++);
           for(int i = 0;i<len;i++){
            if(str[1]==str[0]){
                for(q = 0;q<len;q++){
                    if(str[q]!=str[0]){
                        k2=q;
                        break;
                    }
                }
            }
            if(q!=len&&q!=0)
            printf("%d %d
    ",k2,k2);
            break;
           }
    
    
           get_next();
                 k1= len-next[len];//k为子川的长度
                  ans = len / (len-next[len]);//ans为共有几个这个的子串
                 for(int i = 2;i<=ans;i++)
                            printf("%d %d
    ",i*k1,i);
         printf("
    ");
        }
        return 0;
    }
    



  • 相关阅读:
    [置顶] win7 && win8 下安装SqlServer 2008出现错误无法将对象实例化的问题
    [置顶] sizeof()和c++中变量们
    [置顶] sql2008 附加数据库 .mdf 出现错误 解决方案
    [置顶] 漂亮的 tab 样式
    [置顶] 认识指针和指针变量
    [置顶] SqlHelper类
    [置顶] 第一次使用事物 利用线性表
    [置顶] 设计模式之单例模式 (Design patterns of the The singleton pattern)c#
    [置顶] ListBox控件的数据绑定
    RedHat 6.0(64位)如何使用CentOS YUM源更新的方法
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/7256394.html
Copyright © 2020-2023  润新知