时间限制:1000ms
单点时限:1000ms
内存限制:64MB
描述
小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。
这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?”
小Ho奇怪的问道:“什么叫做最长回文子串呢?”
小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串啦~”
小Ho道:“原来如此!那么我该怎么得到这些字符串呢?我又应该怎么告诉你我所计算出的最长回文子串呢?
小Hi笑着说道:“这个很容易啦,你只需要写一个程序,先从标准输入读取一个整数N(N<=30),代表我给你的字符串的个数,然后接下来的就是我要给你的那N个字符串(字符串长度<=10^6)啦。而你要告诉我你的答案的话,只要将你计算出的最长回文子串的长度按照我给你的顺序依次输出到标准输出就可以了!你看这就是一个例子。”
提示一 提示二 提示三 提示四- 样例输入
-
3 abababa aaaabaa acacdas
- 样例输出
-
7 5 3
传说中的Manacher算法,算法的核心就在这一句上了:p[i] = min(p[2*id-i], p[id] + id - i);
if( mx > i)
p[i]=MIN( p[2*id-i], mx-i);
就是当前面比较的最远长度mx>i的时候,P[i]有一个最小值。这个算法的核心思想就在这里,为什么P数组满足这样一个性质呢?
(下面的部分为图片形式)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int N; 5 string s; 6 7 void solve() { 8 string s1; 9 s1.resize(2 * s.size() + 2); 10 s1[0] = '$'; 11 s1[1] = '#'; 12 for (int i = 0; i < s.size(); ++i) { 13 s1[(i + 1) << 1] = s[i]; 14 s1[((i + 1) << 1) + 1] = '#'; 15 } 16 vector<int> p(s1.size(), 0); 17 int res = 0; 18 for (int id = 0, i = 1; i < s1.size(); ++i) { 19 if (p[id] + id > i) p[i] = min(p[2 * id - i], p[id] + id - i); 20 else p[i] = 1; 21 while (s1[i + p[i]] == s1[i - p[i]]) ++p[i]; 22 if (i + p[i] > id + p[id]) id = i; 23 res = max(res, p[i]); 24 } 25 cout << res - 1 << endl; 26 } 27 28 int main() { 29 cin >> N; 30 while (N--) { 31 cin >> s; 32 solve(); 33 } 34 return 0; 35 }