time limit per test :2 seconds memory limit per test :256 megabytes
input :standard input output :standard output
This is the hard version of the problem. The difference is the constraint on the sum of lengths of strings and the number of test cases. You can make hacks only if you solve all versions of this task.
You are given a string s, consisting of lowercase English letters. Find the longest string, t, which satisfies the following conditions:
The input consists of multiple test cases. The first line contains a single integer t (), the number of test cases. The next t lines each describe a test case.
Each test case is a non-empty string s, consisting of lowercase English letters.
It is guaranteed that the sum of lengths of strings over all test cases does not exceed .
For each test case, print the longest string which satisfies the conditions described above. If there exists multiple possible solutions, print any of them.
5
a
abcdfdcecba
abbaxyzyx
codeforces
acbba
a
abcdfdcba
xyzyx
c
abba
In the first test, the string s="a" satisfies all conditions.
In the second test, the string "abcdfdcba" satisfies all conditions, because:
It can be proven that there does not exist a longer string which satisfies the conditions.
In the fourth test, the string "c" is correct, because "c" = "c" + "" and a or b can be empty. The other possible solution for this test is "s".
对于给定的字符串s,求由s的某段前缀和某段后缀连接而成的最长的回文串t
1. 先设l = 1,r = len,从字符串s两端进行暴力匹配,知道找到 l 和 r 第一个不匹配的位置(注意循环时l < r,不然会runtime error)。
while (s[l] == s[r] && l < r){
++ l;
-- r;
}
2. 通过步骤1,我们知道1~l - 1与r + 1~len是对称的,显然一个回文串左右两边加上对称的部分依然是个回文串,所以接下来我们要找左端点在l或者右端点在r的最长回文串(两种情况选最长的,而且回文串最小长度为1)。
3. 如果暴力去找最长回文串,我们要枚举中心,然后向两边扩散,复杂度是,10的六次方显然超时,复杂度应该控制在或者,这题有manacher和字符串hash两种写法,这里先讲manacher写法。
4. manacher模板人人都有,不会manacher的可以先看看模板题理解一下 (算法理解可以去看oi - wiki 或者各种算法书和博客)- 51nod 1089 - 最长回文子串 V2(Manacher算法)- Manacher模板题,重点是如何求从端点开始的最长回文串呢?我们知道p[i]表示i所能向两边延伸的最大长度(包括i),比如abcdcba中d所能延伸的最大长度为4,如果从左端开始的最长字符串,从中心点i一定能延伸到左端点,即中心点的下标i - p[i] = 0(我们在使用manacher时填充了特殊字符,所以不是-1),右端点同理。
for (int i = 0; i <= 2 * tot + 1; ++ i){
if (i - p[i] == 0) len1 = p[i] - 1;
}
for (int i = 2 * tot + 1; i >= 0; -- i){
if (i + p[i] - 1 == 2 * tot + 1) len2 = p[i] - 1;
}
5. 最后输出即可
for (int i = 1; i < l; ++ i) printf ("%c", s[i]);
if (len1 >= len2){
for (int i = l; i <= l + len1 - 1; ++ i) printf("%c", s[i]);
}else {
for (int i = r - len2 + 1; i <= r; ++ i) printf("%c", s[i]);
}
for (int i = r + 1; i <= len; ++ i) printf("%c", s[i]);
printf("\n");
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e6 + 10;
char s[N];
char t[N], ma[N << 1];
int p[N << 1];
void manacher(char *s, int len){
int l = 0;
ma[l ++] = '$';
ma[l ++] = '#';
for (int i = 1; i <= len; ++ i){
ma[l ++] = s[i];
ma[l ++] = '#';
}
ma[l] = 0;
int r = 0, c = 0;
for (int i = 0; i <= l; ++i){
p[i] = r > i ? min(p[2 * c - i], r - i) : 1;
while (ma[i - p[i]] == ma[i + p[i]]) ++ p[i];
if (i + p[i] > r){
r = i + p[i];
c = i;
}
}
}
int main()
{
int cas;
cin >> cas;
while (cas --){
scanf("%s", s + 1);
int len = strlen(s + 1);
int l = 1, r = len;
while (s[l] == s[r] && l < r){
++ l;
-- r;
}
int tot = 0;
for (int i = l; i <= r; ++ i){
t[++ tot] = s[i];
}
for (int i = 0; i <= 2 * tot + 1; ++ i)p[i] = 0;
manacher(t, tot);
int len1 = 0, len2 = 0;
for (int i = 0; i <= 2 * tot + 1; ++ i){
if (i - p[i] == 0) len1 = p[i] - 1;
}
for (int i = 2 * tot + 1; i >= 0; -- i){
if (i + p[i] - 1 == 2 * tot + 1) len2 = p[i] - 1;
}
for (int i = 1; i < l; ++ i) printf ("%c", s[i]);
if (len1 >= len2){
for (int i = l; i <= l + len1 - 1; ++ i) printf("%c", s[i]);
}else {
for (int i = r - len2 + 1; i <= r; ++ i) printf("%c", s[i]);
}
for (int i = r + 1; i <= len; ++ i) printf("%c", s[i]);
printf("\n");
}
return 0;
}