Prefix-Suffix Palindrome (Hard version)
题意:
- 给定一个串 ,找出一个回文串 ,使得 = + ,并且 的长度不大于 .
思路:
- 我们找到最大的 ,使得
- 串 去掉第一步找到的 和 ,记剩下的中间的子串为 . 我们接下来的任务是找串 的最长前缀回文,或者最长后缀回文。
- 我们知道KMP的前缀数组: 表示 最大相同前后缀的长度。所以利用这一点我们可以求 的 数组, 即为最长前缀回文的长度。
- 至于为什么中间要加一个 ,是因为 数组是前后缀可以交叉的最大相同前后缀的长度,如果中间不隔开,那么可能会造成得到的最长前缀回文是非法的。
样例:uwwuw
#include <bits/stdc++.h>
using namespace std;
const int maxN = 2000100;
int Next[maxN];
void GetNext(string t, int len)
{
int i = 0, j = -1;
Next[0] = -1;
while(i < len)
{
if(j == -1 || t[i] == t[j])
{
++i; ++ j;
if(t[i] != t[j])
Next[i] = j;
else
Next[i] = Next[j];
} else j = Next[j];
}
}
int main()
{
int t;
while(cin >> t)
{
while(t -- )
{
string str, L, R, ans1, ans2;
cin >> str;
int len = str.length();
for(int i = 0; i < len / 2; ++ i )
{
if(str[i] == str[len - 1 - i])
R += str[i];
else
break;
}
L = R;
reverse(R.begin(), R.end());
int lenLR = R.length(), lenMid = len - lenLR * 2;
string _sub = str.substr(lenLR, lenMid), sub = _sub;
reverse(_sub.begin(), _sub.end());
lenMid = lenMid << 1 | 1;
GetNext(sub + '#' + _sub, lenMid);
ans1 = L + sub.substr(0, Next[lenMid]) + R;
GetNext(_sub + '#' + sub, lenMid);
ans2 = L + _sub.substr(0, Next[lenMid]) + R;
if(ans1.length() > ans2.length())
cout << ans1 << endl;
else
cout << ans2 << endl;
}
}
return 0;
}