Problem - 1326D2 - Codeforces
题目大意:给定你一个长度为 n n n的字符串,找出一个该字符串的一个前缀和一个后缀,使得这两个子串拼接成的字符串是一个回文串,求满足以上条件的最长回文串。
解题思路:首先是双指针匹配字符串的左右两端,如果值相等直接加入答案,如果不相等的话,那就从这个地方要找一个回文子串来重新构成回文串了。
当前情况下要不是从左边去匹配找到一个回文串,要不就是从右边去匹配找到一个回文串,具体的难点在于,如何优化查找回文串的复杂度。
这里用的方式是hash,通过将前缀和后缀进行hash,来比较前缀和后缀的hash值,如果相等则判断是回文串。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define syncfalse ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N = 1e6+5;
ll pre[N], suf[N], poww[N];
char s[N];
const int rr = 2333;
const int mod = 999999797;
void solve(){
cin>>s+1;
int n = strlen(s+1);
pre[0]=suf[n+1]=0;
for (int i = 1; i <= n; ++i)pre[i]=(pre[i-1]*rr+(s[i]-'a'+1))%mod;
for (int i = n; i >= 1; --i)suf[i]=(suf[i+1]*rr+(s[i]-'a'+1))%mod;
string left, right, tem;
int l = 1, r = n;
while(l<=r){
if (s[l]!=s[r])break;
if (l==r)left+=s[l];
else {
left+=s[l];
right+=s[l];
}
l++;r--;
}
int len1 = 0, tar1=0;
for (int i = l; i < r; ++i){
ll hashp=(pre[i]-pre[l-1]*poww[i-l+1]%mod+mod)%mod;
ll hashs=(suf[l]-suf[i+1]*poww[i-l+1]%mod+mod)%mod;
if (hashp==hashs&&(i-l+1)>len1){
len1=i-l+1;
tar1=i;
}
}
int len2 = 0, tar2 = n;
for (int i = r; i > l; --i){
ll hashp=(pre[r]-pre[i-1]*poww[r-i+1]%mod+mod)%mod;
ll hashs=(suf[i]-suf[r+1]*poww[r-i+1]%mod+mod)%mod;
if (hashp==hashs&&(r-i+1)>len2){
len2=r-i+1;
tar2=i;
}
}
cout << left;
if (len1>len2){
for (int i = l; i <= tar1; ++i)cout << s[i];
}else{
for (int i = tar2; i <= r; ++i)cout << s[i];
}
reverse(right.begin(), right.end());
cout << right << "\n";
}
int main(){
syncfalse
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
poww[0]=1;
for (int i = 1; i <= 1e6; ++i){
poww[i]=poww[i-1]*rr%mod;
}
int t;
cin>>t;
for (;t;--t){
solve();
}
return 0;
}