双倍快乐(回文树)

Zweib很喜欢回文串,每当看见回文串,他就会觉得很快乐。当且仅当字符串z首位倒置后仍然与原来的串z完全相同时,z 被称为回文串,例如 abcba,abba,a是回文串,而 ab,abcca不是回文串。

这一天Zweib突发奇想,如果用有一个字符串 t是由2个非空的回文串 x 和 y 组成的(,>0),不就可以获得双倍的快乐了吗(迫真突发奇想),于是他想从一个给定的字符串 s 中找出一个子串 t 满足 t 由2个回文串组成,但是他不知道自己能取到的 t 最长为多少,你能帮帮他吗?

ps:当 t 满足 t 是 s 中一串连续的字符组成的字符串时,t 被称为 s 的子串。显然 s 本身也是自己的子串。

题解:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int maxn=3e5+100;
int a[maxn];
ll f[maxn];
ll p[maxn];
ll cal (int l,int r) {
    if (l==0) return f[r];
    return f[r]-f[l-1]*p[r-l+1];
}
bool check (int l,int r) {
    int mid=(l+r)>>1;
    if ((r-l+1)&1)
        return cal(l,mid)==cal(mid,r);
    else
        return cal(l,mid)==cal(mid+1,r);
    //分别判断
}
int Hash[maxn];//表示起点为i的回文串的最大长度
struct palin_Tree {
    //回文树
    int nxt[maxn][26];
    int fail[maxn];
    int len[maxn];
    int cnt[maxn];
    int S[maxn];
    int ind[maxn];
    int last,id,n;
    /*
     * 一个节点表示一个本质不同的回文串
     * len[i]表示回文串i的长度
     * nxt[i][c]表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号
     * cnt[i]表示节点i表示的本质不同的串的个数
     * fail[i]表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串
     * last表示新添加一个字母后形成的最长回文串表示的节点
     * S[i]表示第i次添加的字符
     * ind[i]表示第i号节点是插入到第ind[i]号字符串产生的节点
     */
    int newNode (int x) {
        for (int i=0;i<26;i++)
            nxt[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 (!nxt[cur][c]) {
            int u=newNode(len[cur]+2);
            fail[u]=nxt[getfail(fail[cur])][c];
            nxt[cur][c]=u;
        }
        last=nxt[cur][c];
        cnt[last]++;
        ind[last]=n;
    }
    int getMax () {
        int Max=0;
        for (int i=id-1;i>=0;i--) cnt[fail[i]]+=cnt[i];
        for (int i=0;i<id;i++)
            //if (check(ind[i]-len[i],ind[i]-1))
            //   a[len[i]]+=cnt[i]
                Hash[ind[i]-len[i]]=max(Hash[ind[i]-len[i]],len[i]);
        for (int i=id-1;i>=0;i--)
            if (len[i]>=0&&Hash[ind[i]]) Max=max(Max,len[i]+Hash[ind[i]]);
        return Max;
    }
}Palin_Tree;
char s[maxn];
int main () {
    p[0]=1;
    for (int i=1;i<maxn;i++) p[i]=p[i-1]*13331;
    while (~scanf("%s",s)) {
        int ans=0;
        memset(Hash,0,sizeof(Hash));
        int len=strlen(s);
        for (int i=0;i<=len;i++) a[i]=0;
        Palin_Tree.init();
        for (int i=0;i<len;i++) Palin_Tree.insert(s[i]);
        f[0]=s[0];
        for (int i=1;i<len;i++)
            f[i]=f[i-1]*13331+s[i];
        ans=max(ans,Palin_Tree.getMax());

        memset(Hash,0,sizeof(Hash));
        len=strlen(s);
        for (int i=0;i<=len;i++) a[i]=0;
        Palin_Tree.init();
        for (int i=len-1;i>=0;i--) Palin_Tree.insert(s[i]);
        f[0]=s[0];
        for (int i=1;i<len;i++)
            f[i]=f[i-1]*13331+s[i];
        ans=max(ans,Palin_Tree.getMax());
        cout<<ans<<"\n";
    }
}

 

posted @ 2020-05-13 12:32  zlc0405  阅读(315)  评论(0编辑  收藏  举报