洛谷4555-回文串
link:https://www.luogu.com.cn/problem/P4555
题:顺序和逆序读起来完全一样的串叫做回文串。比如 acbca 是回文串,而 abc 不是:abc 的顺序为 abc,逆序为 cba,不相同。输入长度为 \(n\) 的串 \(S\),求 \(S\) 的最长双回文子串 \(T\),即可将 \(T\) 分为两部分 \(X, Y\)(\(|X|,|Y|≥1\))且 \(X\) 和 \(Y\) 都是回文串。\(2\leq |S|\leq 10^5\)。
在manacher处理后的字符串上考虑(即相邻字符中间插入一个特殊字符)枚举左边的回文中心 \(i\),假设回文半径为 \(r_i\) ,则需要再找一个 \(j>i\) 且以它为中心的回文半径至少能覆盖到 \((i+r_i-1)+1\) 的位置,即 \(j-r_j+1\leq i+r_i\),此时对答案的贡献为:前面一个串 \(r_i-1\),后一个串 \(j-(i+r_i)+1\),需要注意两个串非空(特殊性),即这两个部分都至少是1才能计入答案(否则会被hack掉)
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
vector<int> manacher(string s) {
string t="#";
for(auto c:s)t+=c,t+='#';
int n=t.size();
vector<int> r(n);
for(int i=0,j=0;i<n;i++){
if(2*j-i>=0&&j+r[j]>i)r[i]=min(r[2*j-i],j+r[j]-i);
while(i-r[i]>=0&&i+r[i]<n&&t[i-r[i]]==t[i+r[i]])r[i]++;
if(i+r[i]>j+r[j])j=i;
}
return r;
}
struct Fenwick{
int n;
vector<int> tr;
void init(int _n=0){n=_n;tr.assign(n+1,-1);}
int lowbit(int x){return x&-x;}
int query(int x){
x++;int ret=0;
for(;x;x-=lowbit(x))ret=max(ret,tr[x]);
return ret;
}
void modify(int x,int v){
x++;
for(;x<=n;x+=lowbit(x))tr[x]=max(tr[x],v);
}
}tr;
int main(){
fastio;
string s;cin>>s;
auto r=manacher(s);
int n=r.size(),ans=0;
tr.init(n+5);
for(int i=n-1;i>=0;i--){
int p=tr.query(i+r[i]);
if(p!=-1&&r[i]-1>=1&&p-i-r[i]+1>=1)ans=max(ans,r[i]-1+(p-i-r[i]+1));
tr.modify(max(0,i-r[i]+1),i);
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号