國家集訓隊 最長雙回文串

2022-03-27 07:33:05 字數 1190 閱讀 4860

可能還是非常板子的\(manacher\)

還是先跑一遍\(manacher\)處理出來所有的回文半徑\(r[i]\)

由於我們要找的答案是兩個回文串拼了起來,所以我們考慮列舉中間這個拼接處

所以我們要找到每乙個\(i\),其左邊能夠到達\(i\)的和右邊能到達\(i\)的最大的回文半徑

顯然並不能直接使用\(i+r[i]\)和\(i-r[i]\)因為回文半徑可以是比\(r[i]\)小的,用小的回文半徑可以拼出更大的雙回文串

顯然如果\(i+r[i]-1\)也是可以使用\(i\)為中心的回文半徑的,只不過回文半徑長度是\(r[i]-1\)

\(i+r[i]-2\)同理,是\(r[i]-2\)

所以我們可以直接處理出乙個字尾最大值,每次傳遞的時候\(beh[i]=max(beh[i],beh[i+1]-1)\)也就是讓上乙個回文延續過來只不過長度減少了\(1\)

\(i-r[i]\)同理

**

#include#include#include#define re register

#define maxn 200005

#define ll long long

#define min(a,b) ((a)<(b)?(a):(b))

#define max(a,b) ((a)>(b)?(a):(b))

inline int read()

char s[maxn<<1];

int n;

int r[maxn<<1];

int pre[maxn<<1],beh[maxn<<1];

int main()

for(re int i=1;i<=n;i++)

pre[i-r[i]]=max(pre[i-r[i]],r[i]),beh[i+r[i]]=max(beh[i+r[i]],r[i]);

for(re int i=1;i<=n;i++) pre[i]=max(pre[i],pre[i-1]-1);

for(re int i=n;i;i--) beh[i]=max(beh[i+1]-1,beh[i]);

int ans=0;

for(re int i=1;i<=n;i++)

if(pre[i]&&beh[i])ans=max(ans,pre[i]+beh[i]);

std::cout

}

國家集訓隊 最長雙回文串

題意是 求字串 a b c 且 c 在序列中 a 和 b 都是回文串 運用了回文字串優美的性質 刪掉任意兩個相同的字元仍然回文且長度減2 看到這題之後 我在想 如果把 a 字串的末尾 設為 a 的長度 b 字串的開始 設為 b 的長度 然後 設 a 字串的 右端點 代表的長度為 r i 設 b 字串...

國家集訓隊 最長雙回文串

嘟嘟嘟 這道題,我的大致思想是先用manacher求出所有回文串,然後用剛好拼接在一起的兩個回文串的總長的最大值更新答案。manacher是o n 的,但是暴力的列舉回文中心能達到o n2 所以得想辦法優化列舉。令pre i 表示離 i最遠且左半部分包含 i 的回文串的回文中心的位置,suf i 表...

國家集訓隊 最長雙回文串 馬拉車

傳送門 輸入長度為n的串s,求s的最長雙回文子串t,即t可分為兩部分x和y且x和y都是回文串。考慮列舉中間的斷點,所以我們只要記錄以i為開頭的最長回文串和以i為結尾的最長回文串。通過中心和長度求開頭已經在 這篇 裡面講過了,這裡不再贅述。結尾也只需自己慢漫推一推也可出來。可是以某個位置為開頭的最長回...