<学习笔记>manacher算法
来源:互联网 发布:淘宝买欢乐豆 编辑:程序博客网 时间:2024/06/10 10:45
我是吐槽,你看不到我~~ (*/ω\*) 清北学堂学习第七天来了个特别漂亮的小姐姐(syq)讲了字符串算法,如 kmp,manacher,hash…还特别安利说manacher可以O(n)复杂度解决回文子串问题233 上课只顾着看小姐姐了。下午考试她说有上午学的一部分内容,说帮我们巩固一下。道理我都懂,可是上来第一题就是manacher算法是要闹那样啊,内流满面T^T。。。我上午只看了看思想啊QAQ。。。一定要把模板保存下来。。。
回文串问题
最长回文子串问题:给定一个字符串,求它的最长回文子串长度(n<=10^7)
*回文串:正序和逆序相等的串。从中心轴出发左右对称,中心轴可以是一个字符,也可以是两个字符间的一个间隙。
暴力吗?
枚举每个子串暴力判断…n^3 !!
那优化一下?
枚举中心轴看最长扩展长度。
那字符间隙呢?
在字符间隙里再插上一个#就好了… n^2!(保证#在原串中没有出现过)
还能优化吗?
发现形如 ababababa 发现枚举第3个b时的回文串在枚举第三个a时已经被匹配过一遍了,考虑能不能像kmp算法一样利用之前的匹配信息?
答案是可以的!
Manacher算法
在O(n)时间内,计算出一个字符串以每个位置为中心轴(一个字符或者字符间隙)最长能扩展出多长的回文串。
预处理:将所有的字符都转为奇数长度。
aba–> #a#b#a#
abba–>#a#b#b#a#
另,设r[i]为以i为中心轴的最长匹配半径(不包括i)
栗子:
# a # b # a #
0 1 0 3 0 1 0
# a # b # b # a #
0 1 0 1 4 1 0 1 0
发现r[i]恰好就是以i为中心的最长回文串长度。
能否快速求出r?
定义两个变量:
pos=一个当前向右延伸的位置最远的回文串的中心轴。
maxn_r=这个中心轴的r。
前提:i>pos
计算r[i]时分三种情况讨论:
① i < maxn_r 时: 取i关于pos的对称点j
由回文串性质,可知
⑴ 若r[j]+i<=maxn_r , r[i]=r[j];
⑵若r[j]+i>maxn_r,
可知 i~maxn_r一段一定是回文串。
从maxn_r+1开始逐位匹配并更新maxn _r和pos。
maxn_r=i+r[i],pos=i;
② i>=maxn_r时 从i往右开始逐位匹配,maxn _r=i+r[i],pos=i;
代码:
void Manacher(){ l=strlen(b); for(int i=0;i<l;++i) { a[i<<1]='#'; a[i<<1|1]=b[i]; } l=l*2+1; a[l-1]='#'; maxn_r=0,pos=0; for(int i=0;i<l;++i) { if(maxn_r>i) r[i]=min(maxn_r-i,r[2*pos-i]); else r[i]=0; while(i+r[i]+1<l&&i-r[i]-1>=0&&a[i+r[i]+1]==a[i-r[i]-1]) r[i]++; if(r[i]+i>maxn_r) { maxn_r=r[i]+i; pos=i; } }}
一道简单题
题目描述
小 A 是个学渣,很快就要到 3000 年 NOIprofessional 初赛了,然而他什么题都不会写。
于是他开始研究往年卷的选项分布(然并卵)。
小 A 有 M 份试题。 由于是 professional 版本的考试,初赛试题题目数量 N 非常大。 小
A 发现,某些年份的答案序列里有很多长度超过 k 的回文子串。 极长回文子串 str 定义
为以答案序列 s 中不存在与 str 同对称轴的更长回文子串。 小 A 想知道,每个年份的答
案序列里有多少长度超过 k 的极长回文子串。
输入格式
第一行两个数字 M,k,表示试卷数和长度下限 k
接下来 M 行,每行一个正整数和一个字符串,表示试题的年份和答案,答案序列不区
分大小写。
输出格式
输出共 M 行,每行两个数,第一个数为年份,第二个数为长度超过 k 的极长回文子串
的数量。按照数量递减,数量相同时年份递增的顺序输出。
样例输入
5 3
2011 bacddcb
2000 cacac
2012 aaacdadd
2008 dcdaa
1999 abcda
样例输出
2000 3
2012 2
2008 1
2011 1
1999 0
格式要求
输入文件 Xuezha.in
输出文件 Xuezha.out
时间限制:1s 内存限制:256MB
数据范围
年份 Y,2000<=Y<3000
对于 30%的数据,1<=M<=10,1<=N<=100,1<=k<=100
对于 100%的数据,1<=M<=100,1<=k<=100000,1<=N<=100000
模板题呦φ(>ω<*)
特别注意!!!题目里是不区分大小写的!!!就是说数据里有大写!!就这一点全场wa了一片,没几个有分的QAQ。 wa的一声就哭了。。。
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;int maxn_r,pos,l,k,K,M;int r[200050];char a[200050],b[100050];struct maple{ int year; long long num;}Paper[120];bool cmp(maple a,maple b){ if(a.num==b.num) return a.year<b.year; else return a.num>b.num;}void Done(){ l=strlen(b); for(int i=0;i<l;++i) { a[i<<1]='#'; if(b[i]>='A'&&b[i]<='Z') a[i<<1|1]=b[i]-'A'+'a'; // 单独写会T , mengbi else a[i<<1|1]=b[i]; } l=l*2+1; a[l-1]='#'; maxn_r=0,pos=0; for(int i=0;i<l;++i) { if(maxn_r>i) r[i]=min(maxn_r-i,r[2*pos-i]); else r[i]=0; while(i+r[i]+1<l&&i-r[i]-1>=0&&a[i+r[i]+1]==a[i-r[i]-1]) r[i]++; if(r[i]+i>maxn_r) { maxn_r=r[i]+i; pos=i; } }}int main(){ freopen("Xuezha.in","r",stdin); freopen("Xuezha.out","w",stdout); scanf("%d%d",&M,&K); for(int i=1;i<=M;++i) { scanf("%d",&Paper[i].year); Paper[i].num=0; scanf("%s",b); // 这里用cin,cout也会T Done(); for(int j=0;j<l;++j) if(r[j]>=K) ++Paper[i].num; } sort(Paper+1,Paper+M+1,cmp); for(int i=1;i<=M;++i) { printf("%d %lld\n",Paper[i].year,Paper[i].num); } return 0;}
- <学习笔记>manacher算法
- Manacher算法——学习笔记
- manacher算法理解笔记
- Manacher算法笔记
- 【笔记+模板】 manacher算法
- Manacher算法学习
- 寻找最长回文子串Manacher算法学习笔记
- Manacher 回文自动机 学习笔记
- 数据结构学习笔记4-最长回文子串(Manacher算法)
- Manacher算法
- Manacher算法
- Manacher算法
- Manacher算法
- Manacher 算法
- manacher算法
- manacher 算法
- Manacher算法
- manacher算法
- SpringMVC日期类型转换问题三大处理方法归纳
- Linux常用指令
- 作业 | 什么是敏捷过程?
- 理解RESTful架构
- 用python写的小游戏
- <学习笔记>manacher算法
- 1067. 试密码(20)
- 记录自已学习之面试题5
- python 数据可视化练习
- Android解析WindowManagerService(一)WMS的诞生
- SGU 124. Broken line(射线法判断一个点是否在一个多边形内)
- 【机器学习系列之一】线性回归模型
- MacBook Pro 2017版(带multi-touch bar)安装使用 windows10
- select2 点击清除,清除原来的值