BZOJ 3676: [Apio2014] 回文串 回文树 模版题

 

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 300005; 
struct PAM{//回文树
    int next[maxn][26],fail[maxn],len[maxn],cnt[maxn],S[maxn];
    // 一个结点一个本质不同的回文串 
	//len[i] 表示回文串i的长度 
	// next[i][c]编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号(儿子)。 
	//cnt[i] 节点i表示的本质不同的串的个数
	//(建树时求出的不是完全的,最后重新统计一遍以后才是正确的)。 
	// fail[i] 节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串
	//last 新添加一个字母后所形成的最长回文串表示的节点
	// S[i] 第i次添加的字符(一开始设S[0] = -1,也可以是任意一个在串S中不会出现的字符)
	//2~id-1 添加的结点 n 添加的字符个数
    int id,n,last;
    int newnode(int x){
        for(int i=0;i<26;i++){
            next[id][i]=0;
        }
        cnt[id]=0;
        len[id]=x;
        return id++;
    }
    void init(){
        id=0;
        newnode(0);
        newnode(-1);
        fail[0]=1;
        S[0]=-1;
        last=n=0;
    }
    int getfail(int x){
        while(S[n-len[x]-1]!=S[n]) x=fail[x];
        return x;
    }
    void Insert(int c){
        c-='a';
        S[++n]=c;
        int cur=getfail(last);
        if(!next[cur][c]){
            int now=newnode(len[cur]+2);
            fail[now]=next[getfail(fail[cur])][c];
            next[cur][c]=now;
        }
        last=next[cur][c];
        cnt[last]++;
    }
    ll getsum(){//自下向上更新
    	ll ans = 0; 
        for(int i=id-1;i>=0;i--){
            cnt[fail[i]]+=cnt[i];
            ans = max((ll)cnt[i]*(ll)len[i],ans);
        }
        return ans;
    }
}pam;
char s[maxn];
int main()
{
	scanf("%s",s);
	int len = strlen(s);
	pam.init();
	for(int i=0;i<len;i++)
	{
		pam.Insert(s[i]);
	}
	printf("%lld",pam.getsum());
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wym_king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值