非确定性有穷状态决策自动机练习题Vol.1 A.扭动的回文串

题目描述

\(JYY\)有两个长度均为\(N\)的字符串\(A\)和\(B\)。

一个“扭动字符串\(S(i,j,k)\)由\(A\)中的第\(i\)个字符到第\(j\)个字符组成的子串

与B中的第\(j\)个字符到第\(k\)个字符组成的子串拼接而成。

比如,若\(A\)=’XYZ’,\(B\)=’UVW’,则扭动字符串\(S(1,2,3)\)=’XYVW’。

\(JYY\)定义一个“扭动的回文串”为如下情况中的一个:

1.\(A\)中的一个回文串;

2.\(B\)中的一个回文串;

3.或者某一个回文的扭动字符串\(S(i,j,k)\)

现在\(JYY\)希望找出最长的扭动回文串。

输入格式

第一行包含一个正整数\(N\)。

第二行包含一个长度为\(N\)的由大写字母组成的字符串A。

第三行包含一个长度为\(N\)的由大写字母组成的字符串B。

输出格式

输出的第一行一个整数,表示最长的扭动回文串。

样例

样例输入

5

ABCDE

BAECB

样例输出

5

样例解释

最佳方案中的扭动回文串如下所示(不在回文串中的字符用.表示):

.BC..

..ECB

数据范围与提示

对于\(10\%\)的数据:\(N≤100\);

对于\(30\%\)的数据:\(N≤1000\);

对于\(50\%\)的数据:\(N≤10000\);

对于\(100\%\)的数据:\(1≤N≤10^5\)

分析

对于只在 \(A\) 中的回文串和只在 \(B\) 中的回文串,我们直接拿马拉车 \(O(n)\) 解决即可

比较难处理的是扭动回文串的情况

显然,对于每一个回文串,都有一个回文中心(在马拉车算法前,我们已经把所有的偶回文串填充成了奇回文串)

我们可以把 \(A\) 串和 \(B\) 串中的每一个字符都当作回文中心计算贡献

在马拉车算法后,我们已经求出了以 \(i\) 作为回文中心的最长回文半径 \(f[i]\)

我们只需要在原来的基础上继续向外扩展即可

对于 \(A\) 串中的字符,我们在原串上向左扩展,在 \(B\) 串上向右扩展

对于 \(B\) 串中的字符,我们在原串上向右扩展,在 \(A\) 串上向左扩展

直接暴力去扫肯定会 \(T\) ,我们可以用二分+ \(Hash\) 将扩展的复杂度降为 \(\log(n)\)

对于 \(A\) 我们正着记录一遍哈希值,对于 \(B\) 我们倒着记录一遍哈希值即可

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1e6+5;
typedef unsigned long long ll;
const ll bas=233;
char a[maxn],b[maxn],ksa[maxn],ksb[maxn];
int fa[maxn],fb[maxn],n;
ll hasha[maxn],hashb[maxn],mi[maxn];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int js=0;
ll get_hasha(int l,int r){
return hasha[r]-hasha[l-1]*mi[r-l+1];
}
ll get_hashb(int l,int r){
return hashb[l]-hashb[r+1]*mi[r-l+1];
}
//取哈希值
int solvea(int id){
int l=id-fa[id]+1,r=id+fa[id]-1;
int nl=0,nr=min(l-1,n-r),nmids;
while(nl<=nr){
nmids=(nl+nr)>>1;
if(get_hasha(l-nmids,l)==get_hashb(r-2,r+nmids-2)) nl=nmids+1;
else nr=nmids-1;
}
return fa[id]-1+nr;
}
int solveb(int id){
int l=id-fb[id]+1,r=id+fb[id]-1;
int nl=0,nr=min(l-1,n-r),nmids;
while(nl<=nr){
nmids=(nl+nr)>>1;
if(get_hasha(l-nmids+2,l+2)==get_hashb(r,r+nmids)) nl=nmids+1;
else nr=nmids-1;
}
return fb[id]-1+nr;
}
//对于两个串分别二分
int main(){
n=read();
scanf("%s%s",ksa+1,ksb+1);
n=n*2+1;
a[0]='$',b[0]='$';
for(int i=1;i<=n;i++){
if(i&1) a[i]='#';
else a[i]=ksa[i/2];
}
for(int i=1;i<=n;i++){
if(i&1) b[i]='#';
else b[i]=ksb[i/2];
}
mi[0]=1;
for(int i=1;i<=n;i++){
mi[i]=mi[i-1]*bas;
hasha[i]=hasha[i-1]*bas+a[i];
}
for(int i=n;i>=1;i--){
hashb[i]=hashb[i+1]*bas+b[i];
}
//预处理哈希值
int mids=0,r=0,ans=0;
for(int i=1;i<=n;i++){
if(i<=r) fa[i]=min(fa[mids*2-i],r-i+1);
while(a[i+fa[i]]==a[i-fa[i]]) fa[i]++;
if(i+fa[i]-1>r){
r=i+fa[i]-1,mids=i;
ans=max(ans,fa[i]-1);
}
}
mids=0,r=0;
for(int i=1;i<=n;i++){
if(i<=r) fb[i]=min(fb[mids*2-i],r-i+1);
while(b[i+fb[i]]==b[i-fb[i]]) fb[i]++;
if(i+fb[i]-1>r){
r=i+fb[i]-1,mids=i;
ans=max(ans,fb[i]-1);
}
}
//马拉车
for(int i=1;i<=n;i++){
ans=max(ans,solvea(i));
ans=max(ans,solveb(i));
}
printf("%d\n",ans);
return 0;
}

非确定性有穷状态决策自动机练习题Vol.1 A.扭动的回文串的更多相关文章

  1. 非确定性有穷状态决策自动机练习题Vol.2 C. 奇袭

    非确定性有穷状态决策自动机练习题Vol.2 C. 奇袭 题目描述 由于各种原因,桐人现在被困在\(Under World\)(以下简称\(UW\))中,而\(UW\)马上 要迎来最终的压力测试--魔界 ...

  2. 非确定性有穷状态决策自动机练习题Vol.3 D. Dp搬运工3

    非确定性有穷状态决策自动机练习题Vol.3 D. Dp搬运工3 题目描述 给定两个长度为 \(n\) 的排列,定义 \(magic(A,B)=∑_{i=1}^nmax(Ai,Bi)\) . 现在给定 ...

  3. [火星补锅] 非确定性有穷状态决策自动机练习题Vol.3 T3 && luogu P4211 [LNOI2014]LCA 题解

    前言: 这题感觉还是很有意思.离线思路很奇妙.可能和二次离线有那么一点点相似?当然我不会二次离线我就不云了. 解析: 题目十分清真. 求一段连续区间内的所有点和某个给出的点的Lca的深度和. 首先可以 ...

  4. [火星补锅] 非确定性有穷状态决策自动机练习题Vol.1 T3 第K大区间 题解

    前言: 老火星人了 解析: 很妙的二分题.如果没想到二分答案.. 很容易想到尝试用双指针扫一下,看看能不能统计答案. 首先,tail指针右移时很好处理,因为tail指针右移对区间最大值的影响之可能作用 ...

  5. [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串

    回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...

  6. 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)

    模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...

  7. 2018.12.15 bzoj3676: [Apio2014]回文串(后缀自动机)

    传送门 对原串建立一个后缀自动机,然后用反串在上面匹配. 如果当前匹配的区间[l,r][l,r][l,r]包裹了当前状态的endposendposendpos中的最大值,那么[l,maxpos][l, ...

  8. [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3396  Solved: 1568[Submit][Statu ...

  9. 【bzoj3676】[Apio2014]回文串 —— 回文自动机的学习

    写题遇上一棘手的题,[Apio2014]回文串,一眼看过后缀数组+Manacher.然后就码码码...过是过了,然后看一下[Status],怎么慢这么多,不服..然后就搜了一下,发现一种新东西——回文 ...

随机推荐

  1. vue-methods三种调用的形势

    var btn = { template:`<button>组件add</button>` } var any = new Vue({ el: '#app', data:{ a ...

  2. web自动化 -- HTMLreport(一)测试报告自定义测试用例名,重写ddt

    一.需求痛点 1.HTMLreport测试报告的用例名不明确 2.希望可以自定义HTMLreport测试报告的用例名 3.痛点截图 二.解决办法 1.原因分析 HTMLreport测试报告中的用例名是 ...

  3. Golang获取目录下的文件及目录信息

    一.获取当前目录下的文件或目录信息(不包含多级子目录) func main() {  pwd,_ := os.Getwd() //获取当前目录  //获取文件或目录相关信息  fileInfoList ...

  4. 《Python Web开发实战》|百度网盘免费下载|Python Web开发

    <Python Web开发实战>|百度网盘免费下载|Python Web开发 提取码:rnz4 内容简介 这本书涵盖了Web开发的方方面面,可以分为如下部分: 1. 使用最新的Flask ...

  5. emacs 中文手册 命令行精简版

    man emacs  算是很全了吧.......一些不常用的没有写,不过我感觉没几个没写的.(c-x c-c退出emacs)c-v 下一屏m-v 上一屏c-l 重绘  光标定在屏幕中央(将光标所在的位 ...

  6. It还是高薪行业不?—软件测试

    It还是高薪行业不?—软件测试 谁都希望拿高薪,但是并不是所有人.所有地方都能的:甚者培训出来还不能就业的大有人在,也不是所有人都适合培训后就业(年龄.学历.专业.期望就业地点.不同行业转行还是有很大 ...

  7. functools 中的 reduce 函数基本写法

    reduce 返回的往往是一整个可迭代对象的 操作结果 reduce(函数,可迭代对象) 注:lambda x,y 两个参数 2020-05-04

  8. PHP serialize() 函数

    serialize() 函数用于序列化对象或数组,并返回一个字符串.高佣联盟 www.cgewang.com serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型 ...

  9. C/C++编程笔记:C语言实现连连看游戏,小白练手项目(源码分享)

    本篇文章分享看题目就知道是写给初学者的,学的比较好的小伙伴也可以将自动算法等一些知识给加进去,希望对大家有帮助! 好了,当我们所有的准备工作做好之后,我们就可以来编写我们的C语言连连看游戏了! 其实这 ...

  10. source命令用法:source FileName

    转自https://zhidao.baidu.com/question/59790034.html  写得很清楚,就直接搬过来了备忘 作用:在当前bash环境下读取并执行FileName中的命令. 注 ...