Theme Section
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
To get well prepared for the festival, the hosts want to know the maximum possible length of the theme section of each song. Can you help us?
5 xy abc aaa aaaaba aaxoaaaaa
0 0 1 1 2
题意是保证前缀后缀相同的情况下,求这个前缀或者后缀长度最多能多长并保证前缀后缀中间还有一个这样的与前缀后缀相同的字符串。
一开始理解错了,以为是分成三段都是前缀相同。结果一直做不出来,看了一眼别人的做法,发现自己理解错了。
这个一想就知道用KMP会很简单,看还有人用EKMP,索性我也学着写了一下。
得到next数组后直接遍历找最大值,但是这个最大值需要满足的条件就是对应的i小于i且小于next[i]且小于(len - i) / 2,前两个约束条件很简单就能想明白,而最后一个约束条件是为了防止中间那段和后缀重叠所做的。这样最后我们只需要对后三分之一直接遍历一遍找到所有next[i] + i = len的点,如果该点对应的next[i]小的话,需要更新最大值。
代码如下:
/************************************************************************* > File Name: Theme_Section.cpp > Author: ZhangHaoRan > Mail: chilumanxi@gmail.com > Created Time: 2016年03月11日 星期五 17时47分33秒 ************************************************************************/ #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<vector> #include<set> #include<map> #include<queue> #include<list> #include<algorithm> using namespace std; char str[1000010]; int nexti[1000010]; int len; void pre_EKMP(){ nexti[0] = len; int j = 0; while(j + 1 < len && str[j] == str[j + 1]) j ++; nexti[1] = j; int k = 1; for(int i = 2; i < len; i ++){ int p = nexti[k] + k - 1; int l = nexti[i - k]; if(i + l < p + 1) nexti[i] = l; else{ j = max(0, p - i + 1); while(i + j < len && str[i + j] == str[j]) j ++; nexti[i] = j; k = i; } } } int T; int main(void){ cin >> T; while(T --){ cin >> str; len = strlen(str); pre_EKMP(); int ans = 0; int maxlen = 0; for(int i = 1; i < len; i ++){ maxlen = min(i, nexti[i]); maxlen = min(maxlen, (len - i) / 2); ans = max(ans, maxlen); } int res = 0; for(int i = len - len / 3; i < len ; i ++){ if(nexti[i] + i != len) continue; if(ans >= nexti[i]){ res = nexti[i]; break; } } cout << res << endl; } return 0; }
查看原文:http://chilumanxi.org/2016/03/11/hdu-4673-theme-section/