BZOJ2342:[SHOI2011]双倍回文
浅谈\(Manacher\):https://www.cnblogs.com/AKMer/p/10431603.html
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2342
假设我已经将原字符串的\(p\)数组求好了。
双倍回文肯定是#\(W\)#\(W^R\)#\(W\)#\(W^R\)#
我们枚举中间一个#,求在它的回文半径的一半以内最靠前的第一个满足\(i+p_i-1\geqslant pos\)的第一个#,那么肯定第三个#也是存在的,然后用这个更新答案即可。
怎么快速找到第一个#呢?并查基优化即可。如果一个位置的\(i+p_i-1< pos\)那么显然这个位置也不可能作为后面的#号的第一个#,直接用并查基把他和下一个位置合起来即可。
时间复杂度:\(O(\alpha n)\)
空间复杂度:\(O(n)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e6+5;
int n,ans;
char s[maxn];
int p[maxn],fa[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
int find(int x) {
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
int main() {
n=read();
scanf("%s",s+1);
for(int i=n;i;i--)
s[i<<1]=s[i],s[(i<<1)-1]='#';
s[n<<1|1]='#',s[0]='$',n=n<<1|1;
int id=0,mx=0;
for(int i=1;i<=n;i+=2)fa[i]=i;
for(int i=1;i<=n;i++) {
p[i]=i<=mx?min(mx-i+1,p[(id<<1)-i]):1;
while(s[i-p[i]]==s[i+p[i]])p[i]++;
if(i+p[i]-1>mx)id=i,mx=i+p[i]-1;
if(s[i]=='#'&&p[i]>=5) {
int st=i-p[i]/2;if(st%2==0)st|=1;
for(int j=find(st);j<=i;j=find(j+2))
if(j+p[j]<=i) fa[j]=find(j+2);
else {ans=max(ans,(i-j)<<1);break;}
}
}
printf("%d\n",ans);
return 0;
}
根据洛谷一大佬的题解,此题有\(O(n)\)做法,只需要在\(mx\)被更新的时候枚举旧的\(mx\)到新的\(mx\)之间的点做双倍回文的右端点,新的\(id\)作为双倍回文的中点,然后判断对称过去是不是个回文即可。这样子做双倍回文肯定会被枚举到,并且枚举的总时间就是\(mx\)的改变量。
时间复杂度:\(O(n)\)
空间复杂度:\(O(n)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e6+5;
int n,ans;
int p[maxn];
char s[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
int main() {
n=read();
scanf("%s",s+1);
for(int i=n;i;i--)
s[i<<1]=s[i],s[(i<<1)-1]='#';
s[n<<1|1]='#',s[0]='$',n=n<<1|1;
int id=0,mx=0;
for(int i=1;i<=n;i++) {
p[i]=i<=mx?min(mx-i+1,p[(id<<1)-i]):1;
while(s[i-p[i]]==s[i+p[i]])p[i]++;
if(i+p[i]-1>mx) {
if(s[i]=='#') {
int st=mx+1;if(s[st]!='#')st++;
for(int j=st;j<=i+p[i]-1;j+=2) {
int pos=i+(j-i)/2;pos=(i<<1)-pos;
if(s[pos]=='#'&&p[pos]+pos-1>=i)ans=max(ans,j-i);
}
}
id=i,mx=i+p[i]-1;
}
}
printf("%d\n",ans);
return 0;
}
BZOJ2342:[SHOI2011]双倍回文的更多相关文章
- BZOJ2342 Shoi2011 双倍回文 【Manacher】
BZOJ2342 Shoi2011 双倍回文 Description Input 输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容. Output 输 ...
- BZOJ2342: [Shoi2011]双倍回文
2342: [Shoi2011]双倍回文 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 923 Solved: 317[Submit][Status ...
- BZOJ2342[Shoi2011]双倍回文——回文自动机
题目描述 输入 输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容. 输出 输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文 ...
- bzoj千题计划306:bzoj2342: [Shoi2011]双倍回文 (回文自动机)
https://www.lydsy.com/JudgeOnline/problem.php?id=2342 解法一: 对原串构建回文自动机 抽离fail树,从根开始dfs 设len[x]表示节点x表示 ...
- BZOJ2342:[SHOI2011]双倍回文(Manacher)
Description Input 输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容. Output 输出文件只有一行,即:输入数据中字符串的最长 ...
- [BZOJ2342] [Shoi2011]双倍回文(manacher)
传送门 manacher...... 先跑一边manacher是必须的 然后枚举双倍回文串的对称轴x 把这个双倍回文串分成4段,w wR w wR 发现,只有当 y <= x + p[x] / ...
- bzoj2342: [Shoi2011]双倍回文 pam
题解:先建pam,然后在fail树上dfs,从上到下的链如果有当前长度最远回文串的一半,那么更新答案 //#pragma GCC optimize(2) //#pragma GCC optimize( ...
- 【BZOJ-2342】双倍回文 Manacher + 并查集
2342: [Shoi2011]双倍回文 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1799 Solved: 671[Submit][Statu ...
- 【BZOJ2342】双倍回文(回文树)
[BZOJ2342]双倍回文(回文树) 题面 BZOJ 题解 构建出回文树之后 在\(fail\)树上进行\(dp\) 如果一个点代表的回文串长度为\(4\)的倍数 并且存在长度为它的一半的回文后缀 ...
- 2018.06.30 BZOJ 2342: [Shoi2011]双倍回文(manacher)
2342: [Shoi2011]双倍回文 Time Limit: 10 Sec Memory Limit: 128 MB Description Input 输入分为两行,第一行为一个整数,表示字符串 ...
随机推荐
- 自己动手编译Android源码(超详细)
http://www.jianshu.com/p/367f0886e62b 在Android Studio代码调试一文中,简单的介绍了代码调试的一些技巧.现在我们来谈谈android源码编译的一些事. ...
- Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介
转:https://www.cnblogs.com/shoemaker/p/linux_graphics02.html 1. Framebuffer Framebuffer驱动提供基本的显示,fram ...
- 快乐学习 Ionic Framework+PhoneGap 手册1-2{介绍Header,Content,Footer的使用}
*先运行第一个简单的APP,介绍Header,Content,Footer的使用 {2.1}运行一个简单的APP,效果如下 {2.2}Header代码 <ion-header-bar class ...
- node中session存储与销毁,及session的生命周期
1.首先在使用session之前需要先配置session的过期时间等,在入口文件app.js中 app.use(express.session({ cookie: { maxAge: config.g ...
- webstrom上运行node项目配置操作
其实特别简单.... 去webtrom主界面找到下图的按钮,点击 点击之后弹框如下: 点击左上方绿色加号,如下图,点击node.js 点击之后,填写下图中内容: 点击应用,主界面的绿色开始按钮就可以用 ...
- R的几个基础函数
本章目录: 1.路径和文件 2.数据转换 3.获得帮助 路径和文件: 1.工作路径: 显示当前路径:getwd() 设置路径:setwd(“绝对路径”) 2.目录: 创建目录:dir.create(& ...
- TortoiseSVN教程级别指南
安装说明 开发人员强烈建议使用IDE中的SVN插件更加智能与人性化. 首先安装SVN客户端,windows一般选择乌龟客户端https://tortoisesvn.net/downloads.html ...
- Elasticsearch6.4.3安装
Linux内存一定要1g以上! 首先要有jdk环境 要求1.8版本以上 elasticsearch是Java写的 将上传的 elasticSearch安装包解压 cd /home/elastics ...
- XXL-Job路由策略
企业项目中所有的任务调动通过XXL-Job 去管理调度 路由策略类似于Nginx哦 XXL-Job实际封装的是Quartz. 关于分片广播,执行器集群部署时候,任务路由策略选择“”分片广播”情况下,一 ...
- volist/foreach下,点击循环中的一个进行操作
第一种方法,是给点击元素绑定事件,用ajax将值传到控制器中,其中传的值,用jquery选择器选择值. 1.在html中 <foreach name="save" item= ...