zoukankan      html  css  js  c++  java
  • 【POJ1961 Period】【KMP】

    题面

    一个字符串的前缀是从第一个字符开始的连续若干个字符,例如"abaab"共有5个前缀,分别是a, ab, aba, abaa, abaab。

    我们希望知道一个N位字符串S的前缀是否具有循环节。换言之,对于每一个从头开始的长度为 i (i 大于1)的前缀,是否由重复出现的子串A组成,即 AAA...A (A重复出现K次,K 大于 1)。如果存在,请找出最短的循环节对应的K值(也就是这个前缀串的所有可能重复节中,最大的K值)。

    算法

    我们看到这个前缀 自然想到了KMP中的next数组(请不要在实际使用中使用next关键字)
    如果一个字符串S是由一个字符串T重复K次形成的,则称T是S的循环元。使K最大的字符串T称为S的最小循环元,此时的K称为最大循环次数。
    现在给定一个长度为N的字符串S,对S的每一个前缀S[1~i],如果它的最大循环次数大于1,则输出该前缀的最小循环元长度和最大循环次数。

    当i-next[i]能整除i时,S[1i-next[i]]就是S[1i]的最小循环元。它的最大循环次数就是i/(i-next[i])。
    进一步地,如果i-next[next[i]]能整除i,那么S[1i-next[next[i]]]就是S[1i]的次小循环元。
    以此类推我们还可以找出S[1~i]所有可能的循环元。

    代码

    01
    #include<vector>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<string>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int maxn = 1000000 + 10;
    char s[maxn];
    int f[maxn];
    int main()
    {
        int n,cas=1;
        while(scanf("%d",&n)==1&&n){
            scanf("%s",s);
            //求fail数组
            f[0]=f[1]=0;
            for(int i=1;i<n;i++){
                int j=f[i];
                while(j&&s[i]!=s[j]) j=f[j];
                f[i+1]=(s[i]==s[j])?j+1:0;
            }
            printf("Test case #%d
    ",cas++);
            for(int i=2;i<=n;i++){
                int length=i-f[i]; //循环节长度
                if(f[i]>0&&i%length==0) printf("%d %d
    ",i,i/length);
            }
            printf("
    ");
        }
        return 0;
    }
    
    
  • 相关阅读:
    float浮动
    数据库基础操作
    Python re 模块
    I/O模型的使用
    函数形参与实参
    内置函数重写_运算符重载
    导入模块_导入包_标准库模块
    异常处理
    闭包
    函数式编程
  • 原文地址:https://www.cnblogs.com/dixiao/p/13747214.html
Copyright © 2011-2022 走看看