• KMP求字符串最小循环节


    证明1:

    对于一个字符串S,长度为L,如果由长度为len的字符串s(字符串s的最小循环节是其本身)循环k次构成,那么字符串s就是字符串S的最小循环节

    那么字符串有个很重要的性质和KMP挂钩,即  i - next[i] 为字符串s的长度 i%(i - next[i]) ==0

    证明:字符串S由s循环k次构成,那么有S[0-->L-len-1] == S[len-->L-1],即前k-1个循环节和后k-1个循环节构成的字符串相等

    那么此时KMP数组的next[L] = k-1个循环节的长度, 也即 next[L] = L-len-1+1 = L - len,那么此时 L - next[L] = len , 所以 L % len = 0,   L % len = k

    所以如果字符串存在循环节,那么i % (i - next[i]) ==0,循环节的长度为  i - next[i]

    否则,循环节的为字符串本身。

     证明2:

    t = n-next[n] 为循环节的长度
    1、如果next[n]==0,则表示字符串S前后无任何相同的部分,所以字符串S自身为一个循环节,成立
    2、如果next[n]!=0  且 字符串S的循环节个数为2
     ①:如果字符串S是完美(即每个循环节都是完整的)
      那么next[n] = n/2    所以 t = n - next[n] = n/2,成立
     ②:字符串S的循环节个数为2,但是位于左边的循环节是完整的,右边的是残缺的
      那么next[n] = 残缺的循环节和完整的循环节的相似长度,所以t = n - next[n]成立
    3、如果next[n]!=0 且字符串S的循环节个数k>=3 ,
     那么字符串S从第二个循环节开始到最后一个字符(设长度为len)和字符串S从第一个字符串开始的len个字符相等
     所以t = n - next[n]成立

    hdu1358

    求每一个前缀是不是循环串,如果是,输出串长和循环的次数。

     1 #include <stdio.h>
     2 #include <string.h>
     3 const int N = 1000000 + 10;
     4 char str[N];
     5 int next[N];
     6 void makeNext(char *str)
     7 {
     8     int i=0,j=-1;
     9     next[0] = -1;
    10     while(str[i])
    11     {
    12         if(j==-1||str[i]==str[j])
    13         {
    14             i++;
    15             j++;
    16             next[i] = j;
    17         }
    18         else
    19             j = next[j];
    20     }
    21 }
    22 int main()
    23 {
    24     
    25     int n;
    26     int tCase = 1;
    27     while(true)
    28     {
    29         scanf("%d",&n);
    30         if(n==0)
    31             break;
    32         scanf("%s",str);
    33         makeNext(str);
    34         printf("Test case #%d
    ",tCase++);
    35         for(int i=2; i<=n; ++i)
    36         {
    37             if(i%(i-next[i])==0 && next[i]!=0)//next[i]!=0,如果为0,循环节是本身
    38                 printf("%d %d
    ",i,i/(i-next[i]));
    39             
    40         }
    41         puts("");
    42         
    43     }
    44     return 0;
    45 }

    hdu3746

    补多少个字符能形成循环串

     1 #include <stdio.h>
     2 #include <string.h>
     3 const int N = 100000   + 10;
     4 
     5 char str[N];
     6 int next[N];
     7 
     8 void makeNext()
     9 {
    10     int i = 0,j = -1;
    11     next[i] = j;
    12     while(str[i])
    13     {
    14         if(j==-1 || str[i]==str[j])
    15             next[++i] = ++j;
    16         else
    17             j = next[j];
    18     }
    19 }
    20 int main()
    21 {
    22     int t;
    23     scanf("%d",&t);
    24     while(t--)
    25     {
    26         scanf("%s",str);
    27         int n = strlen(str);
    28         makeNext();
    29         int t = n - next[n];
    30         if(t!=n && n%t==0)
    31             puts("0");
    32         else
    33             printf("%d
    ",t-(n-n/t*t));
    34     }
    35     return 0;
    36 }
  • 相关阅读:
    [USACO09Open] Tower of Hay 干草塔
    [HNOI2004]打鼹鼠
    BZOJ1222[HNOI 2001]产品加工
    BZOJ1270[BJWC2008]雷涛的小猫
    NOIP2018出征策
    解析·NOIP·冷门 CLZ最小环
    CCF-NOIP-2018 提高组(复赛) 模拟试题(九)(2018 CSYZ长沙一中)
    [脚本无敌1]图片批量处理(matlab)
    用Matlab解《2013年数据建模比赛》图像碎片拼接题
    火灾检测-fire,fire
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4035361.html
Copyright © 2020-2023  润新知