D2. Prefix-Suffix Palindrome (Hard version)
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 ss, consisting of lowercase English letters. Find the longest string, tt, which satisfies the following conditions:
- The length of tt does not exceed the length of ss.
- tt is a palindrome.
- There exists two strings aa and bb (possibly empty), such that t=a+bt=a+b ( "++" represents concatenation), and aa is prefix of ss while bb is suffix of ss.
Input
The input consists of multiple test cases. The first line contains a single integer tt (1≤t≤1051≤t≤105), the number of test cases. The next tt lines each describe a test case.
Each test case is a non-empty string ss, consisting of lowercase English letters.
It is guaranteed that the sum of lengths of strings over all test cases does not exceed 106106.
Output
For each test case, print the longest string which satisfies the conditions described above. If there exists multiple possible solutions, print any of them.
Example
input
Copy
5 a abcdfdcecba abbaxyzyx codeforces acbba
output
Copy
a abcdfdcba xyzyx c abba
Note
In the first test, the string s=s="a" satisfies all conditions.
In the second test, the string "abcdfdcba" satisfies all conditions, because:
- Its length is 99, which does not exceed the length of the string ss, which equals 1111.
- It is a palindrome.
- "abcdfdcba" == "abcdfdc" ++ "ba", and "abcdfdc" is a prefix of ss while "ba" is a suffix of ss.
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 aa or bb can be empty. The other possible solution for this test is "s".
思路:
前缀回文为a,后缀回文为b,不管a或者b谁为空,首先对原始字符串进行manacher算法处理,当然中间要进行处理,找到最长前缀回文串的长度和最长后缀回文串的长度;并且比较两者长度,将较长的一个作为答案的一部分;
如果a,b都不为空,那么双指针往中间缩动;找到之间不能匹配的一段字符串,然后对其进行manacher算法处理;和上面一样求出长前缀回文串的长度和最长后缀回文串的长度;作为答案的中间的一部分;
#include<bits/stdc++.h>
using namespace std;
const int maxx = 3e6+10;
char tmp[maxx];
int len[maxx];
int s1,s2;
void Manacher(string s)
{
tmp[0]='$';
tmp[1]='#';
int t=s.size();
for(int i=0;i<2*t+5;i++)len[i]=0;
for(int i=1;i<=t;i++)
{
tmp[2*i]=s[i-1];
tmp[2*i+1]='#';
}
tmp[2*t+2]='\0';
int mx=0;
int mid;
for(int i=1;tmp[i];i++)
{
if(i<mx)len[i]=min(len[2*mid-i],mx-i);
else len[i]=1;
while(tmp[i-len[i]]==tmp[i+len[i]])len[i]++;
if(len[i]+i>mx)
{
mx=len[i]+i;
mid=i;
}
int l=len[i]-1;
if(i%2==0)
{
l=(l-1)/2;
int p=i/2;
if(p-l==1)s1=max(s1,len[i]-1);
if(p+l==t)s2=max(s2,len[i]-1);
}
else
{
l=l/2;
int p=(i-1)/2,q=(i+1)/2;
if(p-l+1==1)s1=max(s1,len[i]-1);
if(q+l-1==t)s2=max(s2,len[i]-1);
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
s1=0,s2=0;
string s,ans1,ans2;
cin>>s;
int n=s.size();
Manacher(s);
if(s1>s2) ans1=s.substr(0,s1);
else ans1=s.substr(n-s2,s2);
int i=0,j=n-1;
while(i<j&&s[i]==s[j]) ans2+=s[i],i++,j--;
string ss=s;
if(i<j)
{
s1=0,s2=0;
ss=s.substr(i,j-i+1);
int n=ss.size();
Manacher(ss);
if(s1>s2) ans2+=ss.substr(0,s1);
else ans2+=ss.substr(n-s2,s2);
}
ans2+=s.substr(j+1);
if(ans1.size()>=ans2.size()) cout<<ans1<<endl;
else cout<<ans2<<endl;
}
return 0;
}