[ABC398F] ABCBA 题解

题意

求以字符串 \(S\) 为前缀的最短回文串。

解法

根据回文串的定义,可以将 \(S\) 翻转后(设翻转后的字符串为 \(T\))拼在其后面,但这样不一定是最优的。

显而易见的是,若 \(S\) 的后缀和 \(T\) 的相同长度的前缀相同,\(T\) 的这一前缀去除后不会影响是否满足回文条件。所以,要求最短的长度,就可以转化为求最长满足这个条件的后缀。

方法有很多,下面用的双哈希。

哈希写法
\(H_{s,i,p}\) 为字符串 \(s\)\(i\) 个字符的第 \(p\) 个哈希,则有 \(H_{s,i,p}=B\cdot H_{s,i-1,p}+s_i\),其中 \(B\) 为模数。

\(\operatorname{hash}(s,l,r,p)\) 为字符串 \(s\)\(l\)\(r\) 的第 \(p\) 个哈希,则可以由 \(H\) 推出 \(\operatorname{hash}(s,l,r,p)=H_{s,r,p}-B^{r-l+1}\cdot H_{s,l-1,p}\)

求出两个哈希后,直接枚举后缀长度,对 \(S\) 的后缀和 \(T\) 的前缀求哈希,若都相等则输出。

详见代码。

code

// 流星群に会えた夏
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll b1=10007,b2=10009;

int n;
string s,t;
ll tmp=0;
ll hs[514000][3],ht[514000][3],pb[514000][3];

inline ll hss(int l,int r,int i){
    return hs[r][i]-hs[l-1][i]*pb[r-l+1][i];
}

inline ll hst(int l,int r,int i){
    return ht[r][i]-ht[l-1][i]*pb[r-l+1][i];
}

int main(){
    //ios::sync_with_stdio(false); cin.tie(0);
    cin>>s; n=s.length();
    for(int i=n-1;i>=0;i--) t+=s[i];
    pb[0][1]=1; pb[0][2]=1;
    for(int i=0;i<n;i++){
        hs[i][1]=hs[i-1][1]*b1+s[i];
        ht[i][1]=ht[i-1][1]*b1+t[i];
        hs[i][2]=hs[i-1][2]*b2+s[i];
        ht[i][2]=ht[i-1][2]*b2+t[i];
        pb[i][1]=pb[i-1][1]*b1;
        pb[i][2]=pb[i-1][2]*b2;
    }
    for(int i=n;i>=1;i--){
        if(hss(n-i,n,1)==hst(0,i-1,1)&&hss(n-i,n,2)==hst(0,i-1,2)){
            cout<<s;
            for(int j=i;j<n;j++) cout<<t[j];
            return 0;
        }
    }
    return 0;
}
posted @ 2025-03-29 20:30  _CuSO4  阅读(107)  评论(1)    收藏  举报