zoukankan      html  css  js  c++  java
  • 模板题 + KMP + 求最小循环节 --- HDU 3746 Cyclic Nacklace

    Cyclic Nacklace 

    Problem's Link:  http://acm.hdu.edu.cn/showproblem.php?pid=3746


     

    Mean: 

    给你一个字符串,让你在后面加尽量少的字符,使得这个字符串成为一个重复串。

    例:

    abca---添加bc,成为abcabc

    abcd---添加abcd,成为abcdabcd

    aa---无需添加

    analyse:

    经典的求最小循环节。

    首先给出结论:一个字符串的最小循环节为:len-next[len]。

    证明:

    举个例子:abcabc的最小循环节是abc,abcda的最小循环节是abcd,abbab的最小循环节是abb。

    看出点什么端倪没?

    证明开始:

    -----------------------

    -----------------------

     k    m       x     j       i

    由上,next[i]=j,两段红色的字符串相等(两个字符串完全相等),s[k....j]==s[m....i]

    设s[x...j]=s[j....i] ,记为:(xj=ji)

    则可得,以下简写字符串表达方式:

    kj=kx+xj;

    mi=mj+ji;

    因为xj=ji,所以kx=mj,如下图所示

    -------------

          -------------

     k   m        x     j   

    看到了没,此时又重复上面的模型了,kx=mj,所以可以一直这样递推下去。

    所以可以推出一个重要的性质len-next[len]为此字符串的最小循环节。

    另外如果len%(len-next[len])==0,此字符串的最小周期就为len/(len-next[i])。

    有了这个结论,这题就好做多了。注意判断一下是否原串就是一个重复串。

    Time complexity: O(N)

     

    Source code: 

    /*
    * this code is made by crazyacking
    * Verdict: Accepted
    * Submission Date: 2015-07-27-21.10
    * Time: 0MS
    * Memory: 137KB
    */
    #include <queue>
    #include <cstdio>
    #include <set>
    #include <string>
    #include <stack>
    #include <cmath>
    #include <climits>
    #include <map>
    #include <cstdlib>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #define  LL long long
    #define  ULL unsigned long long
    using namespace std;

    const int MAXN=100010;
    char s[MAXN];
    int Next[MAXN];
    void getNext()
    {
         Next[0]=0;
         int s_len=strlen(s);
         for(int i=1,k=0;i<s_len;++i)
         {
               while(s[i]!=s[k]&&k) k=Next[k-1];
               if(s[i]==s[k]) ++k;
               Next[i]=k;
         }
    }
    int main()
    {
         ios_base::sync_with_stdio(false);
         cin.tie(0);
         int t;
         scanf("%d",&t);
         while(t--)
         {
               scanf("%s",s);
               getNext();
               int s_len=strlen(s);
               int min_cycle=s_len-Next[s_len-1];
               if(min_cycle!=s_len && s_len%min_cycle==0)
               {
                     puts("0");
               }
               else
               {
                     int need_add=min_cycle-Next[s_len-1]%min_cycle;
                     printf("%d ",need_add);
               }
         }
         return 0;
    }
    /*

    */
  • 相关阅读:
    setlocale set the current locale
    测试一个目录下的文件共有多少行
    ping中用到的校验和算法
    atomic integer operations P176
    我要理解1为什么是0xffffffff,所以写了下面的程序理解。
    贝叶斯网络中一个节点的类
    bash 的浮点除法
    shell(1)
    AndroidBroadcast详解与汇总
    AndroidActivity详解与汇总
  • 原文地址:https://www.cnblogs.com/crazyacking/p/4681359.html
Copyright © 2011-2022 走看看