• 字符串习题


    poj 2406:

      这道题出的很好,让我明白了kmp循环节的性质。不过,不知是我太弱,还是网上大牛太多,大家都是直接找到最小的循环节之后就直接判断它是否整除n了。我想了好久,一直不明白一个问题。

      假设最小循环节的长度为D。如果存在长度为d的循环节,它满足d>D且d不是D的倍数,这种情况是怎么判断的(就是存在大于最小循环节且不是最小循环节倍数的循环节)。后来…发现如果存在的话,那么必然存在长度为gcd(d,D)的循环节…然后gcd(d,D)<D,于是就证明出不存在这种情况。

      综上,所有的循环节的长度都必然是最短的循环节的长度的倍数。
      (至于为什么存在长度为gcd(d,D)的循环节,这个就要分d和D是否互质来讨论,而且其中的证明还要用到剩余系。相信了解剩余系的人都能很容易的证明出来,这里就不赘述了。)

     1 //13365733  ooyyloo 2406    Accepted    5248K   125MS   G++ 939B    2014-08-23 14:44:15 (第二次)
     2 //13365580  ooyyloo 2406    Accepted    5248K   79MS    G++ 772B    2014-08-23 14:21:11
     3 #include <cstdlib>
     4 #include <cstdio>
     5 #include <algorithm>
     6 #include <cstring>
     7 #define rep(i, n) for (int i = 0; i < (n); i++)
     8 #define FOR(i,l,r) for (int i = (l); i <= (r); i++)
     9 using namespace std;
    10 const int maxn=1000001;
    11 
    12 int n;
    13 char str[maxn];
    14 int fail[maxn];
    15 int main(){
    16     for (; ; )
    17     {
    18         scanf("%s", str);
    19         if (str[0]=='.') break;
    20         n = strlen(str);
    21         int j = 0;
    22         FOR (i, 2, n)
    23         {
    24             while (j && str[j] != str[i-1]) j = fail[j];
    25             if (str[j] == str[i-1]) j++;
    26             fail[i] = j;
    27         }
    28         /*j = fail[n];
    29         while (j && n % (n-j) != 0) j = fail[j];
    30         if (j == 0) printf("1
    ");
    31         else printf("%d
    ", n / (n - j));*/
    32         if (n % (n-j) == 0) printf("%d
    ", n / (n - j));
    33         else puts("1");
    34     }
    35     return 0;
    36 }
    37 //第二次比第一次的时间复杂度的原因是poj评测机发烧...两种做法时间是一样的
    poj 2406
  • 相关阅读:
    杭电 1013 Digital Roots
    杭电 1040 As Easy As A+B 【排序】
    杭电 2092 整数解
    bzoj3223
    bzoj3224
    LA3905
    bzoj3601
    bzoj1002
    bzoj3105
    bzoj3332
  • 原文地址:https://www.cnblogs.com/monmonde/p/3931114.html
Copyright © 2020-2023  润新知