BZOJ 2342: [Shoi2011]双倍回文 [Manacher + set]

本文介绍了一种算法,通过枚举中间位置并利用Manacher算法来寻找字符串中最长的由四个相同回文串组成的子串。文章详细解释了算法步骤,并提供了完整的C++实现代码。

题意:

求最长子串使得它有四个相同的回文串SSSS相连组成


 

枚举中间x

找右边的中间y满足 y-r[y]<=x y<=x+r[x]/2

用个set维护

注意中间只能是#

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
const int N=1e6+5;
typedef long long ll;
int n;
char s[N],str[N];
int r[N];
void Manacher(char s[],int n){
    int p=0,a;
    for(int i=1;i<=n;i++){
        r[i]=i<p?min(p-i+1,r[2*a-i]):1;
        while(s[i-r[i]]==s[i+r[i]]) r[i]++;
        if(i+r[i]-1>p) p=i+r[i]-1,a=i;
    }
}
void iniStr(char str[],char s[]){
    for(int i=1;i<=n;i++)
        s[(i<<1)-1]='#',s[i<<1]=str[i];
    s[n<<1|1]='#';
    s[0]='@';s[(n<<1)+2]='$';
}
set<int> Set;
set<int>::iterator it;
struct data{
    int v,id;
    bool operator <(const data a)const{return v<a.v;}
}a[N];
int ans;
void solve(){
    n=n<<1|1; int p=0;
    for(int i=1;i<=n;i++) if(i&1) a[++p].v=i-r[i],a[p].id=i;
    sort(a+1,a+1+p);
    int now=1;
    for(int i=1;i<=n;i++) if(i&1){
        while(now<p&&a[now].v<=i) Set.insert(a[now].id),now++;
        it=--Set.upper_bound(i+r[i]/2);
        if(it!=Set.begin()) ans=max(ans,(*it)-i);
    }
    printf("%d",ans*2);
}
int main(){
    freopen("in","r",stdin);
    scanf("%d%s",&n,str+1);
    iniStr(str,s);
    Manacher(s,n<<1|1);
    solve();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值