洛谷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;
}
posted @ 2024-04-02 22:17  yoshinow2001  阅读(47)  评论(0)    收藏  举报