題目
給出一個字符串,從中找出兩個不相交且長度和最大的非空迴文子串,輸出長度和。
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;
}