【牛客練習賽57:D】迴文串(迴文樹求前/後綴最長迴文子串)

傳送門

題目


給出一個字符串,從中找出兩個不相交且長度和最大的非空迴文子串,輸出長度和。
2S2e52≤|S|≤2e5
input

abccbaa

output

7

解題思路


用馬拉車沒解出來,下午複習了下回文樹,(自己沒想出來suf[i]的最長迴文子串怎麼寫🚮)嘗試用xzh的思路。
既然迴文樹的len[i]已經處理出以i爲結尾的最長迴文子串長度,那麼在insert的時候就可以據此求出每個前綴的最長迴文子串長度,倒序處理字符串又可得出每個後綴的最長迴文子串長度,這樣就可以實現子串不相交然後去求答案。
注意迴文樹具體建樹過程,自己寫的時候wa了,還是對迴文樹理解的不夠到位,欠靈活應用。

ac代碼


#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+100;
typedef long long ll;
int fail[maxn], len[maxn], nxt[maxn][30], s[maxn];
int last, n, p, maxlen;
char ss[maxn];
int maxpre[maxn];
int newnode(int l)//l: 節點p對應的最長迴文子子串長度
{
    for(int i = 0; i < 26; i++) nxt[p][i] = 0;
    len[p] = l;
    return p++;
}
void init()
{
    memset(fail, 0, sizeof fail);
    p = last = n = maxlen = 0, s[0] = -1;
    newnode(0);//偶長度迴文串
    newnode(-1);//奇長度迴文串
    fail[0] = 1, fail[1] = 0;
}
int get_fail(int x)
{
    while(s[n-len[x]-1]!=s[n]) x = fail[x];
    return x;
}
void insert(int c, int type)//c=ch-'a'
{
    s[++n] = c;
    int cur = get_fail(last);//last=0, cur=1
    if(!nxt[cur][c])
    {
        int now = newnode(len[cur]+2);
        //初始cur=1, get_fail(fail[cur))=1, fail[now]=0
        fail[now] = nxt[get_fail(fail[cur])][c];
        nxt[cur][c] = now;
    }
    last = nxt[cur][c];
    maxlen = max(maxlen, len[last]);
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    //abbaabbc
    scanf("%s", ss+1);
    int lenn = strlen(ss+1);

    init();
    for(int i = 1; i <= lenn; i++)
    {
        insert(ss[i]-'a', 0);
        maxpre[i] = maxlen;
    }

    init();
    int ans = 0;
    for(int i = lenn; i > 1; i--)
    {
        insert(ss[i]-'a', 1);
        ans = max(ans, maxpre[i-1]+maxlen);//min(i-1)=1
    }
    printf("%d\n", ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章