最长双回文串 bzoj 2565 回文自动机

题目

顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。

分析

先把串S正着做一次回文自动机
得到数组len_pro
len_pro[i]表示以S[i]结尾的最长回文子串

接着把串S反着做一次回文自动机
得到数组len_nex
len_nex[i]表示从S[i]开始的最长回文子串

然后枚举分割点即可

code

#include
#include
#include
#include
#include
#include
#define maxn 500005  
#define maxm 600005 
#define INF 0x7fffffff;

using namespace std;

int next[maxn][30],fail[maxn],len[maxn],num[maxn];
int mx1[maxn],mx2[maxn];
long long cnt[maxn]; 
int S[maxn];

int last;

int N=0;
int p=0;

void newnode(int l)
{
    ++p;
    for (int i=1;i<=26;i++) next[p][i]=0;
    len[p]=l;
    num[p]=0;
    cnt[p]=0;
}

int get_fail(int x)
{
    while (S[N-len[x]-1]!=S[N]) x=fail[x];
    return x;
}

void add(char C)
{
    int c=C-'a'+1;
    S[++N]=c;
    int cur=get_fail(last);
    if (!next[cur][c])
    {
        newnode(len[cur]+2);
        fail[p]=next[get_fail(fail[cur])][c];
        next[cur][c]=p;
        num[p]=num[fail[p]]+1;
    }
    last=next[cur][c];
    mx1[N]=len[last];
    cnt[last]++;
}

void count()
{
    for (int i=p;i>=0;i--) cnt[fail[i]]+=cnt[i] ;
}

int main()
{
    string s;
    cin>>s;
    p=-1;
    newnode(0);
    newnode(-1);
    last=0; N=0;
    S[N]=-1; fail[0]=1; 
    for (int i=0;i1]=mx1[i+1];
    }
    count();
    memset(next,0,sizeof(next));
    memset(fail,0,sizeof(fail));
    memset(len,0,sizeof(len));
    memset(num,0,sizeof(num));
    memset(cnt,0,sizeof(cnt));
    memset(mx1,0,sizeof(mx1));
    memset(S,0,sizeof(S));
    p=-1;
    newnode(0);
    newnode(-1);
    last=0; N=0;
    S[N]=-1; fail[0]=1;
    for (int i=s.length()-1;i>=0;i--)
    {
        add(s[i]);
    }

    int ans=0;
    for (int i=1;i<=s.length();i++)
    {
        int k=mx2[i]+mx1[s.length()-(i+1)+1];
        if (k>ans) ans=k;
    }
    cout<

你可能感兴趣的:(c++,bzoj,回文自动机)