题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3746
题目描述:
给定一个字符串S,问至少需要添加多少个字符,使得新字符串拥有两个以上的循环节。
解题思路:
又一个next数组的应用(由于next数组在C++内不能使用,所以我使用失配数组也即fail数组,其实两个数组都是一样的)。计算得出next数组后,由于题目要求在原字符串右边添加字符,所以直接看最后一个字符的next值,最后一个字符的next值可以分两种情况:
1.next = 0.这种情况表示字符串中不存在公共前后缀,那么要得到两个循环节就只能再添加一段原字符串了。
2.next > 0.这种情况表明我们只需要在字符串后添加原字符串的子串就可以得到合法的字符串了,那么问题来了,这个子串究竟是多长呢?已知该next值就是字符串最长公共前后缀长度,那么去掉后缀的那一部分字符串就是循环节啦。因为如果那部分字符串不是循环节,那么就没有公共前后缀啦。所以知道了循环节的长度,就只需要与原字符串长度进行比较就可以知道要添加多少字符啦。
代码:
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <cstring> 5 #include <vector> 6 #include <algorithm> 7 using namespace std; 8 9 #define ll long long 10 #define INF 0x3f3f3f3f3f 11 #define MAX 100100 12 13 char T[MAX]; 14 int fail[MAX]; 15 16 void getFail() 17 { 18 fail[0] = 0; 19 int k = 0; 20 int len = strlen(T); 21 for(int i = 1; i < len; ++i) { 22 while(k > 0 && T[i] != T[k]) 23 k = fail[k - 1]; 24 if(T[i] == T[k]) 25 k++; 26 fail[i] = k; 27 } 28 } 29 30 int main() 31 { 32 //freopen("debug\\in.txt", "r", stdin); 33 //freopen("CON", "w", stdout); 34 int i, j, k; 35 int test; 36 scanf("%d", &test); 37 while(test--) { 38 scanf("%s", T); 39 //memset(fail, 0, sizeof(fail)); 40 int len = strlen(T); 41 getFail(); 42 if(fail[len-1] == 0) { 43 printf("%d\n", len); 44 continue; 45 } 46 int t = len - fail[len-1]; 47 if(len % t == 0) 48 printf("0\n"); 49 else 50 printf("%d\n", t - len % t); 51 } 52 return 0; 53 }
HDU 3746 - Cyclic Nacklace(KMP)
原文:http://www.cnblogs.com/lc520love/p/5294152.html