下面先介紹man
ache
rmanacher
manach
er演算法。假設str
strst
r為待處理字串,len
[i
]len[ i ]
len[i]
陣列存放以該str
[i
]str[ i ]
str[i]
字元為中心的最長回文半徑,mid
midmi
d為當前最長回文子串的中點,mxmx
mx為當前最長回文子串的右邊界.。
在開始演算法之前,先在字串中首部填充$,字元之間#。比如,字串abaaba填充之後就變成了$#a#b#a#a#b#a#($與#未在字串**現)。
那麼對當前位置 i
ii有如下偽**:(此時已經知道前i−1
i - 1
i−1個字元的最長回文半徑)
若i
i < mx
i,則l en
[i]=
min(
len[
2×mi
d−i]
,mx−
i)
len[ i ] = min ( len[ 2 \times mid - i ] , mx - i )
len[i]
=min
(len
[2×m
id−i
],mx
−i)。
否則l en
[i]=
1len[ i ] = 1
len[i]
=1。對i
ii位置上的字元向兩邊進行匹配,更新len
[i
]len[ i ]
len[i]
的值,更新結束後更新mid
midmi
d和mx
mxmx
的值。
命題:如果i
i < mx
i,那麼i
ii為中心的最長回文半徑最少為min
(len
[2×m
id−i
],mx
−i
)min ( len[ 2 \times mid - i ] , mx - i )
min(le
n[2×
mid−
i],m
x−i)
。證明:
首先i
i < mx
i說明i
ii坐落於以mid
midmi
d為中心的回文子串中。在該回文子串範圍內,左右兩邊是完全對稱的,所以i
ii的最長回文半徑可參考其對稱點2×m
id−i
2 \times mid - i
2×mid−
i的最長回文半徑。
已知其對稱點2×m
id−i
2 \times mid - i
2×mid−
i最長回文半徑為min
(len
[2×m
id−i
],mx
−i
)min ( len[ 2 \times mid - i ] , mx - i )
min(le
n[2×
mid−
i],m
x−i)
,所以i
ii的最長回文半徑至少為min
(len
[2×m
id−i
],mx
−i
)min ( len[ 2 \times mid - i ] , mx - i )
min(le
n[2×
mid−
i],m
x−i)
,超出mxmx
mx的部分暴力匹配即可。
$#a#b#a#a#b#a#中以#為中心的最長回文子串去掉#後對應原字串的最長偶回文串,以原字元為中心的最長回文子串去掉#後對應原字串的最長奇回文串。而去掉#後的最長回文串的長度正好等於回文半徑減1
11,這樣問題轉化為了求$#a#b#a#a#b#a#的最長回文半徑。
由於每個字元只會被匹配一次,所以時間複雜度為o(n
)\mathcal(n)
o(n)
。
#include
#include
#include
#include
using
namespace std;
const
int maxn=
110010
;char s[maxn]
,ma[maxn*2]
;int mp[maxn*2]
;int
manacher
(char
*s,int len)
return res;
}int
main()
return0;
}
HDU 3068 最長回文
題 目 鏈 接 看完後自己寫了一遍,感覺真的是很神奇的結論啊!本來這題看到可以用字尾陣列來寫的,但沒有學過,去看了一下,真心給暈了,決定找個機會認真研究下。我的 include include includeusing namespace std define min a,b a b a b cha...
HDU 3068 最長回文
存在o n 的演算法,學習了一下 include include includeusing namespace std const int maxn 300011 int n,p maxn char str maxn in maxn int main str 0 str 1 n n 2 2 str ...
HDU 3068 最長回文
problem description 給出乙個只由小寫英文本元a,b,c.y,z組成的字串s,求s中最長回文串的長度.回文就是正反讀都是一樣的字串,如aba,abba等 input 輸入有多組case,不超過120組,每組輸入為一行小寫英文本元a,b,c.y,z組成的字串s 兩組case之間由空行...