BZOJ.2565.[国家集训队]最长双回文串(Manacher/回文树)
求给定串的最长双回文串。
\(n\leq10^5\)。
Manacher:
记\(R_i\)表示以\(i\)位置为结尾的最长回文串长度,\(L_i\)表示以\(i\)开头的最长回文串长度。答案就是\(\max\{R_i+L_{i+1}\}\)。式子可能会有差别,因为Manacher会在里面加字符。当然我们直接只用'#'位置的\(L_i+R_i\)就可以更新答案啦。
Manacher,然后对于位置\(i\),设它的最远延伸距离是\(ex_i\)。
然后用\(i-j\)更新\(L_j,\;j\in[i-ex_i+1,\ i]\),\(j-i\)更新\(R_j,\;j\in[i,i+ex_i-1]\)(注意字符串里加了'#'的)。
显然只需要维护更新它的\(\max\{i\},\min\{i\}\)就可以了,可以用线段树。(当然我懒得去写)
但这个做法显然不够好,考虑能否\(O(1)\)更新,也就是更新一个位置然后递推过来。(表示没想出来= =)
可以啊...更新\(i-j\)这个值,相邻两个位置是相差\(1\)的。而从\(j\)更新到\(i\)位置时,\(i-j\)就\(\leq0\)了。也就是我们只更新\(L_{i-ex_i+1}=\max\{ex_i-1\}\),最后用\(L_j=\max\{L_j,\ L_{j-1}-1\}\)递推即可。\(R\)同理。
这样就\(O(n)\)啦。
当然我们只需要在'#'处统计,所以只更新这些位置即可。
回文树:
对正反串建两次回文树,求出每个位置的最长回文长度就可以了。。
Manacher:
//3360kb 84ms
#include <cstdio>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=2e5+5;
int ex[N],L[N],R[N];
char s[N];
int Build()
{
int n=strlen(s+1);
for(int i=n; i; --i) s[i<<1]=s[i], s[(i<<1)-1]='#';
s[0]='!', s[n<<1|1]='#', s[(n<<1)+2]='@';
return n<<1|1;
}
void Manacher(const int n)
{
for(int i=1,id,mx=0; i<=n; ++i)
{
if(i<mx) ex[i]=std::min(ex[2*id-i],mx-i);
else ex[i]=1;
while(s[i-ex[i]]==s[i+ex[i]]) ++ex[i];
if(i+ex[i]>mx) mx=i+ex[i], id=i;
L[i-ex[i]+1]=std::max(L[i-ex[i]+1],ex[i]-1);
R[i+ex[i]-1]=std::max(R[i+ex[i]-1],ex[i]-1);
}
}
int main()
{
scanf("%s",s+1);
int n=Build(); Manacher(n);
for(int i=n-2; i>=1; i-=2) R[i]=std::max(R[i],R[i+2]-2);//i>=1 not i!
for(int i=3; i<=n; i+=2) L[i]=std::max(L[i],L[i-2]-2);
int ans=0;
for(int i=1; i<=n; i+=2) if(L[i]&&R[i]) ans=std::max(ans,L[i]+R[i]);//if!
printf("%d\n",ans);
return 0;
}
回文树:
//23576kb 156ms
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=1e5+5;
char s[N];
struct PAM
{
int las,tot,fail[N],son[N][26],len[N],mx[N];
PAM() {tot=1, fail[0]=1, len[1]=-1;}
inline int Find(int x,int n)
{
while(s[n-len[x]-1]!=s[n]) x=fail[x];
return x;
}
void Insert(int c,int n)
{
int p=Find(las,n);
if(!son[p][c])
{
int np=++tot; fail[np]=son[Find(fail[p],n)][c];
son[p][c]=np, len[np]=len[p]+2;
}
las=son[p][c];
}
void Build(char *s,const int n,const int opt)
{
if(opt) for(int i=1; i<=n; ++i) Insert(s[i]-'a',i), mx[i]=len[las];
else for(int i=1; i<=n; ++i) Insert(s[i]-'a',i), mx[n-i+1]=len[las];//...
}
}p1,p2;
int main()
{
scanf("%s",s+1); int n=strlen(s+1);
p1.Build(s,n,1), std::reverse(s+1,s+1+n), p2.Build(s,n,0);
int ans=0;
for(int i=1; i<n; ++i) ans=std::max(ans,p1.mx[i]+p2.mx[i+1]);
printf("%d\n",ans);
return 0;
}
BZOJ.2565.[国家集训队]最长双回文串(Manacher/回文树)的更多相关文章
- Manacher || P4555 [国家集训队]最长双回文串 || BZOJ 2565: 最长双回文串
题面:P4555 [国家集训队]最长双回文串 题解:就.就考察马拉车的理解 在原始马拉车的基础上多维护个P[i].Q[i]数组,分别表示以i结尾最长回文子串的长度和以i开头的最长回文子串的长度 然后就 ...
- P4555 [国家集训队]最长双回文串
P4555 [国家集训队]最长双回文串 manacher 用manacher在处理时顺便把以某点开头/结尾的最长回文串的长度也处理掉. 然后枚举. #include<iostream> # ...
- 洛谷 P4555 [国家集训队]最长双回文串 解题报告
P4555 [国家集训队]最长双回文串 题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为\(n\)的串 ...
- 【洛谷】P4555 [国家集训队]最长双回文串
P4555 [国家集训队]最长双回文串 题源:https://www.luogu.com.cn/problem/P4555 原理:Manacher 还真比KMP好理解 解决最长回文串问题 转化为长度为 ...
- Manacher【p4555】 [国家集训队]最长双回文串
题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为 n 的串 S ,求 S 的最长双回文子串 T ,即可 ...
- [国家集训队]最长双回文串 manacher
---题面--- 题解: 首先有一个直观的想法,如果我们可以求出对于位置i的最长后缀回文串和最长前缀回文串,那么我们枚举分界点然后合并前缀和后缀不就可以得到答案了么? 所以我们的目标就是求出这两个数列 ...
- P4555 [国家集训队]最长双回文串(回文树)
题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为 n 的串 S ,求 S 的最长双回文子串 T ,即可 ...
- luoguP4555 [国家集训队]最长双回文串 manacher算法
不算很难的一道题吧.... 很容易想到枚举断点,之后需要处理出以$i$为开头的最长回文串的长度和以$i$为结尾的最长回文串的长度 分别记为$L[i]$和$R[i]$ 由于求$R[i]$相当于把$L[i ...
- 【洛谷 P4555】 [国家集训队]最长双回文串 (Manacher)
题目链接 \(|S|<=10^5\),时间还是很宽松的. 允许我们使用线性/\(N\log N\)/甚至\(N \sqrt N\)的算法. 设\(l[i]\)表示以\(a[i]\)结尾的最长回文 ...
随机推荐
- kali linux revealed mastering the penetration testing distribution
1.本博客记载的是这本书的学习笔记,还有出现的一些不懂的单词 我也将会记载这篇博客中.记载顺序是按照本书的章节顺序来记载的.最喜欢本书中的一句 you havae no idea how good ...
- python中range()函数的用法
python中range()函数可创建一个整数列表,一般用在for循环中. range()函数语法: range(start,stop[,step]) 参数说明: star: 计数从star开始.默认 ...
- 关于springboot整合配置pagehelper插件的方法
一,java代码配置法 这种方法个人感觉比较繁琐不是很推荐,而且也不怎么符合springboot的理念,但是胜在也能够用,所以就列起来,万一以后接手的代码是用这种方式的也方便自己维护. 首先引入jar ...
- Android Studio启动时出现unable to access android sdk add-on list
目录 Android Studio First Run 检测 Android SDK 及更新,由于众所周知的原因,我们会「Unable to access Android SDK add-on lis ...
- 一脸懵逼搭建Zookeeper分布式集群
1:首先将http://zookeeper.apache.org/ 下载好的zookeeper-3.4.5.tar.gz上传到三台虚拟机上,之前博客搭建好的(安装Zookeeper之前记得安装好你的j ...
- Windows Docker 使用笔记
1.设置共享盘 2.设置加速器.国内拉取docker镜像会出现卡顿甚至拉不下来的问题,原因在于大陆沿海的一道墙,在docker设置中添加镜像代理(registry-mirrors)PS:镜像加速器地址 ...
- 【SPFA与Dijkstra的对比】CDOJ 1961 咸鱼睡觉觉【差分约束-负权最短路径SPFA】
差分约束系统,求最小值,跑最长路. 转自:https://www.cnblogs.com/ehanla/p/9134012.html 题解:设sum[x]为前x个咕咕中至少需要赶走的咕咕数,则sum[ ...
- order by 导出数据不一致的问题
转自 http://blog.csdn.net/wwwwei_csdn/article/details/78181197 前言 数据库分页是后台经常要使用的技术手段,有时候进行数据库查询会根据业务 ...
- nginx 域名泛解析
部分应用场景下要求服务器根据客户输入的二级域名地址自动访问不同的页面,比如一个服务器放置了不同的业务,商城.官网等多个业务,又不想一个个配置server, 网站目录结构入戏: html 网站根目录 m ...
- 【ASP.NET】UCenter实现多站点同步登录退出
利用UCenter实现discuz论坛和应用网站同步登录和退出功能 测试环境:Discuz! X3.2.UCenter 1.6..Net Framework 4.0 进入Discuz 后台的UCent ...