• poj1961 Period kmp解决找字符串的最小循环节


    /**
    题目:poj1961 Period
    链接:http://poj.org/problem?id=1961
    题意:求从1到i这个前缀(2<=i<=N) ,如果有循环节(不能自身单独一个),输出前缀字符串长度以及最大的循环周期;
    思路:
    参考自:http://www.cnblogs.com/chenxiwenruo/p/3546457.html
    定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0…len-next[len]-1]。
    
    (1)如果len%(len - next[len])==0,则表明字符串S可以完全由循环节循环组成,循环周期T=len/L。(这里的len就是从0开始的len位置,kmp也计算了next[len]。)
    
    (2)如果不能,说明还需要再添加几个字母才能补全。需要补的个数是循环个数L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。
    
    ----------------------------
    */
    
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <queue>
    #include <iostream>
    #include <vector>
    using namespace std;
    #define ms(x,y) memset(x,y,sizeof x)
    const int N = 1e6 + 10;
    const int inf = 0x3f3f3f3f;
    char s[N];
    int f[N];
    void getFail(char* P,int* f)
    {
        int m = strlen(P+1);
        f[1] = f[2] = 1;
        for(int i = 2; i <= m; i++){
            int j = f[i];
            while(j!=1&&P[i]!=P[j]) j = f[j];
            f[i+1] = (P[i]==P[j])?j+1:1;
        }
    
    }
    int main()
    {
        int n;
        int cas = 1;
        while(scanf("%d",&n)==1&&n)
        {
            scanf("%s",s+1);
            getFail(s,f);
            printf("Test case #%d
    ",cas++);
            for(int i = 3; i <= n+1; i++){
                if((i-1-(f[i]-1))==i-1) continue;//不能以自身为一个循环节。即循环周期至少为2.
                if((i-1)%(i-1-(f[i]-1))==0){
                    printf("%d %d
    ",i-1,(i-1)/(i-1-(f[i]-1)));
                }
            }
            puts("");
        }
        return 0;
    }
  • 相关阅读:
    docker入门
    IAR屏蔽警告的方法
    在MDK 中忽略(suppress) 某一个警告
    stm32 F40x CCM数据区的使用
    如何理解Stand SPI Dual SPI 和Quad SPI??
    stm32F1在sram中调试运行代码
    stm32低功耗的一点总结
    C语言中__attribute__ ((at())绝对定位的应用
    系统栈和任务栈——freertos
    软件模拟spi的注意事项
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7347976.html
Copyright © 2020-2023  润新知