P4445 最長迴文串
題目描述
順序和逆序讀起來完全一樣的串叫做迴文串。比如是迴文串,而不是(abc的順序爲,逆序爲,不相同)。
輸入長度爲的串,求的最長雙迴文子串,即可將分爲兩部分,,且和都是迴文串。
題目解答
將串進行預處理增加’$‘和’#'字符得到串以便使用Manacher算法.
使用Manacher算法求以每個位置爲中心的最長迴文串長度數組.
算法一.
根據數組,處理出數組
表示中以爲右端點的最長迴文串的中心位置.
表示中以爲左端點的最長迴文串的之心位置.
ps:由於字符串中包含了字符,因此迴文串中心到一端的距離,就可以實際表示一個迴文串的長度.
由於串特殊的奇偶性,我們枚舉,計算的最大值就是答案.
問題變成了如何求數組.
以爲例,求法類似:
枚舉迴文串中心的位置,則區間內未設置值得位置全都設置成爲.
實現代碼
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
const int N = 100007;
char s[N],ns[N<<1];int np[N<<1];
#define pr(x) std::cout << #x << ":" << x << std::endl
std::vector<int> vec[N<<1];
int vis[N<<1];
int lft[N<<1],rgt[N<<1];
int Manacher() {
int len = 0,mx = 0,id;
ns[len++] = '$';
ns[len++] = '#';
for(int i = 0;s[i];++i)
ns[len++] = s[i],ns[len++] = '#';
for(int i = 1;i < len;++i) {
np[i] = mx > i ? std::min(np[2*id-i],mx-i):1;
while(ns[i-np[i]] == ns[i+np[i]])
++np[i];
if(np[i]+i > mx)
mx = np[i]+i,id = i;
}
int p = 0;
for(int i = 0;i < len;++i) {
for(;p < i + np[i];++p) {
lft[p] = i;
}
}
p = len;
for(int i = len-1;i > 0;--i) {
for(;p > i - np[i];--p) {
rgt[p] = i;
}
}
int ans = 0;
for(int i = 1;i < len;i++) {
ans = std::max(ans,rgt[i+1] - lft[i]);
}
return ans;
}
int main() {
std::cin >> s;
std::cout << Manacher() << std::endl;
return 0;
}
算法二.
計算數組
表示以爲右端點的最長迴文子串在中的實際長度.
表示以爲左端點的最長迴文子串在中的實際長度.
那麼答案就是枚舉爲偶數,
以爲例,類似:
從小到大枚舉,並用一個優先隊列維護當前最小的迴文串中心點,設定在位置將優先隊列中的設爲失效.
每次從優先隊列中取出的第一個有效的數即是.
這種算法的思路與算法一本質上是一樣的,只不過枚舉量不同,算法一枚舉的是,然後利用單調性將時間複雜度降低到了
算法二枚舉的是,需要用數據結構來維護,時間複雜度是
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
const int N = 100007;
char s[N],ns[N<<1];int np[N<<1];
#define pr(x) std::cout << #x << ":" << x << std::endl
std::vector<int> vec[N<<1];
int vis[N<<1];
int lft[N<<1],rgt[N<<1];
int Manacher() {
int len = 0,mx = 0,id;
ns[len++] = '$';
ns[len++] = '#';
for(int i = 0;s[i];++i)
ns[len++] = s[i],ns[len++] = '#';
for(int i = 1;i < len;++i) {
np[i] = mx > i ? std::min(np[2*id-i],mx-i):1;
while(ns[i-np[i]] == ns[i+np[i]])
++np[i];
if(np[i]+i > mx)
mx = np[i]+i,id = i;
}
for(int i = 0;i < (N << 1);++i) vec[i].clear();
memset(vis,0,sizeof(vis));
std::priority_queue<int,std::vector<int>,std::greater<int> > lQ;
for(int i = 1;i < len;++i) {
for(auto u : vec[i]) vis[u] = 1;
while(!lQ.empty() && vis[lQ.top()]) lQ.pop();
lft[i] = 1;
if(lQ.empty()) {
lQ.push(i);
vec[i + np[i]].push_back(i);
continue;
}
else {
lft[i] = std::max(lft[i],(i-lQ.top()+1)/2*2+(lQ.top()%2==0));
}
lQ.push(i);
vec[i + np[i]].push_back(i);
}
for(int i = 0;i < (N << 1);++i) vec[i].clear();
memset(vis,0,sizeof(vis));
std::priority_queue<int> gQ;
for(int i = len-1;i;--i) {
for(auto u : vec[i]) vis[u] = 1;
while(!gQ.empty() && vis[gQ.top()]) gQ.pop();
rgt[i] = 1;
if(gQ.empty()) {
gQ.push(i);
vec[i - np[i]].push_back(i);
continue;
}
else {
rgt[i] = std::max(rgt[i],(gQ.top()-i+1)/2*2+(gQ.top()%2==0));
}
gQ.push(i);
vec[i - np[i]].push_back(i);
}
int ans = 0;
for(int i = 1;i+2 <= len;++i)
if(i%2==0)
ans = std::max(ans,lft[i]+rgt[i+2]);
return ans;
}
int main() {
std::cin >> s;
std::cout << Manacher() << std::endl;
return 0;
}