HDU-3746 Cyclic Nacklace

题意:给出一个字符串,然后假设其首尾连接,然后求其最小的循环节

思路:

要求循环节,通过运用next数组的含义。已知next数组为在该长度下的最长的相同前后缀长度

然后利用关系式 sum = len - next[len] , sum - len%sum;

然后就是关系式的解释:(关系刚开始理解了很久,主要是有些写的太含糊没有弄清,最后看了这个递归思路就理解了)

例如字符串:

1   2       3   4    5
-------------------++++++++
a b c d | a b c d | a b c d |a b c d       我们先不管其循环大小,先从next数组入手
      -------------------+++++++
已知next  -1 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12   (即上面的化横线加号部分相等)

同时我们知道加号部分相等 (3 4)== (5 6) 那我们同时去掉 即 len - next[len];

1       2       3   4    5
---------+++++++++
a b c d | a b c d | a b c d      又重复上面的模型了 所以如过 len % (len - next[len]) == 0 除余数可以看作递归减去这个长度                    
      ---------++++++++      如果最后减没了则说明这个长度刚好是一个 循环的长度 即是所谓的循环节

所以先判断有没有循环节

有循环节 就可以判断 其是否刚好是循环节构成的 len%sum 即 len % (len - next[len]) == 0 此时就不必再补了 否则就补上 循环节所需的大小

没有循环节 则要补充整个串(以整个串为单位)构成 新的节

 

完整代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;
const int maxn = 1e5+10;
int nex[maxn];
char a[maxn];
int len;
void getnext(){
    int i,j;
    i = 0,j = -1;
    nex[i] = j;
    while(i<len){
        if(j==-1||a[i]==a[j]) {
            nex[++i] =++j;
        }else j = nex[j];
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin>>T;
    while(T--){

        cin>>a;
        len = strlen(a);
        getnext();
        int sum=len-nex[len];
         if (!nex[len]) printf("%d\n",len);
          else
            if (!(len%sum)) printf("0\n");
             else printf("%d\n",sum-len%sum);

    }
} 

 

posted @ 2019-07-18 18:26  Tianwell  阅读(154)  评论(0编辑  收藏  举报