Shoi2011 双倍回文

题目描述

题解:

建出PAM之后倍增跳查。

貌似很裸。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 500050
int n;
char s[N];
struct pnt
{
    int pre,len,trs[27];
}p[N];
struct PAM
{
    int las,tot;
    PAM()
    {
        las = tot = 1;
        p[0].pre=p[1].pre=1;
        p[1].len=-1;
    }
    bool mis(int i,int x)
    {
        return s[i]!=s[i-p[x].len-1];
    }
    void insert(int i)
    {
        int lp = las;
        while(mis(i,lp))lp=p[lp].pre;
        int c = s[i]-'a'+1;
        if(!p[lp].trs[c])
        {
            int np = ++tot;
            int tmp = p[lp].pre;
            while(mis(i,tmp))tmp = p[tmp].pre;
            p[np].pre = p[tmp].trs[c];
            p[np].len = p[lp].len+2;
            p[lp].trs[c] = np;
        }
        las = p[lp].trs[c];
    }
    int fa[N][21];
    void build()
    {
        for(int i=0;i<=tot;i++)fa[i][0]=p[i].pre;
        for(int i=1;i<=20;i++)
            for(int j=0;j<=tot;j++)
                fa[j][i]=fa[fa[j][i-1]][i-1];
    }
    int ans;
    void bfs()
    {
        queue<int>q;
        q.push(0);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            if(p[u].len%4==0)
            {
                int tmp = u;
                for(int i=20;i>=0;i--)
                    if(p[fa[tmp][i]].len*2>=p[u].len)tmp=fa[tmp][i];
                if(p[tmp].len*2==p[u].len)
                    ans=max(ans,p[u].len);
            }
            for(int i=1;i<=26;i++)
                if(p[u].trs[i])q.push(p[u].trs[i]);
        }
    }
    int cal()
    {
        ans=0;
        bfs();
        return ans;
    }
}pam;
int main()
{
    scanf("%d%s",&n,s+1);
    for(int i=1;i<=n;i++)
        pam.insert(i);
    pam.build();
    printf("%d\n",pam.cal());
    return 0;
}

 

转载于:https://www.cnblogs.com/LiGuanlin1124/p/10127179.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值