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); } }