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;
}