Manacher思想 SCOI2013 密码
关于$\mathrm{Manacher}$算法,网上介绍已经很全面 这里说一下自己的理解
这里的$rad$数组:$rad_i$表示以以位置i为中心的最长回文串的回文半径(不包括i这个点)。
朴素的思想大概是从每个点出发像两边扩展,大概$O(n^2)$复杂度?据说$\mathrm{Manacher}$是$O(n)$的(不会证,Orz,大概因为每个位置只会被暴力扩展$O(1)$次)这是因为回文串有对称性,我们可以利用这点来优化算法。现在假设我们已经得到了$i$和$i$以前的$rad$值,现在想直接通过$O(1)$的时间计算出i右边一些点的$rad$值。设$k$从$1$到$rad_i$,表示现在想直接计算出$rad_{i+k}$的$rad$值。则有下列情况
其中
红色:$rad_i$
橙色:$rad_{i-k}$
绿色:$rad_{i-k}$
①$rad_i-k<rad_{i-k}$————————————————————————————————————————————————————————————
此时$rad_{i+k}$一定为$rad_i-k$否则根据对称性,$rad_i$可以更大。
②$rad_i-k>rad_{i-k}$————————————————————————————————————————————————————————————
此时根据对称性也可以很显然地看出$rad_{i+k}=rad_{i-k}$
由①②有,当$rad_i-k\not=rad_{i-k}$时,$rad_{i+k}=\min{\{rad_{i-k},rad_i-k\}}$
那么$rad_i-k=rad_{i+k}$时怎么办呢
③$rad_i-k=rad_{i-k}$————————————————————————————————————————————————————————————
这时即使$rad_{i+k}>rad_{i-k}$也没有矛盾,此时应当令i+=k用朴素的算法扩大$rad_i$之后再用这个$rad_i$迭代更新。
代码:
- for(int i=1,j=0,k;i<=len;){
- for(;s[i-j-1]==s[i+j+1];j++);
- rad[i]=j;
- for(k=1;k<=j && rad[i]-k!=rad[i-k];k++)
- rad[i+k]=min(rad[i]-k,rad[i-k]);
- i+=k;
- j=max(j-k,0);
- }
但是这样只能求出长度为奇数的回文串的长度,对于偶数,我们这样处理。
- char s[Maxn]={0};
- s[0]='*';
- for(int i=0;i<_len;i++){
- s[++len]=_s[i];
- s[++len]='#';
- }
- s[len]='&';
之后再按上面的方法求即可。
然后这里再说一下$\mathrm{SCOI2013}$的密码,用了$\mathrm{Manacher}$的思想。(题目链接http://acm.uestc.edu.cn/#/problem/show/128)
很容易想到朴素的算法,把必须为相同字符的合并为一个集合(用并查集实现),然后对必须不相同的集合连边,从集合向集合中的元素连边。后一步是$O(n)$的,而前一步最坏是$O(n^2)$对于$10^5$的数据显然无法承受,这里很自然想到$\mathrm{Manacher}$的$O(n)$
$i$从$1$开始,维护$rad_i+i$的最大值,为$MX_r$,这样的$i$记为$MX_{id}$,然后显然我们只需要从$i+\max{\{0, \min{\{MX_r-i,rad_{2MX_{id}-i}\}}\}}$开始合并,大概又是$O(n)$的
完整代码
- #include<iostream>
- #include<cstring>
- #include<cstdlib>
- #include<cstdio>
- #include<algorithm>
- #define dout printf
- using namespace std;
- const int Maxn=100000+10;
- int n,rad[Maxn*2];
- int col[Maxn*2],cannot[Maxn*2][30],cnt=0;
- int stk[30],top;
- bool instk[Maxn*2];
- inline void getint(int&x){
- char c=getchar();
- for(x=0;!isdigit(c);c=getchar());
- for(;isdigit(c);c=getchar())x=x*10+c-'0';
- }
- struct Edge{int b;Edge*next;}edges[Maxn*3*2],*firc[Maxn*2],*fird[Maxn*2];int tot;
- void AddEdge(int a,int b,Edge*fir[]){
- edges[++tot]=(Edge){b,fir[a]};fir[a]=edges+tot;
- }
- int fa[Maxn*2];
- int Find(const int&x){
- return fa[x]==x?x:fa[x]=Find(fa[x]);
- }
- bool Union(int x,int y){
- x=Find(x),y=Find(y);
- if(x==y)return 0;
- return fa[y]=x,1;
- }
- void input(){
- getint(n);
- for(int i=1;i<=n;i++)getint(rad[(i<<1)-1]);
- for(int i=1;i<n;i++)getint(rad[i<<1]);
- }
- void work(const int n2=n*2){
- int MX_r=1,MX_id=1;
- char*ans=new char[Maxn];
- memset(ans,0,sizeof(*ans)*Maxn);
- for(int i=1;i<=n2;i++)fa[i]=i;
- for(int i=2;i<=n2;i++){
- for(int j=max(0, min(MX_r-i,rad[MX_id*2-i]) );i-j>0&&i+j<=n2&&j<=rad[i];j++) {
- Union(i-j,i+j);
- }
- if(rad[i]+i>MX_r)MX_r=i+rad[i],MX_id=i;
- }
- for(int f,i=1;f=Find(i),i<=n2;i+=2)
- AddEdge(f,(i+1)>>1,firc);
- for(int f1,f2,d,i=2;i<=n2;i++){
- d=rad[i]+1;
- f1=Find(i-d),f2=Find(i+d);
- AddEdge(f1,f2,fird);
- AddEdge(f2,f1,fird);
- }
- for(int x,real,f,i=1;real=(i+1)>>1,i<=n2;i+=2)if(!ans[real]){
- x=1;f=Find(i);
- for(;cannot[f][x];x++);
- for(Edge*p=fird[f];p;p=p->next)cannot[p->b][x]=1;
- for(Edge*p=firc[f];p;p=p->next)ans[p->b]=x+'a'-1;
- }
- puts(ans+1);
- delete ans;
- }
- int main(){
- freopen("password.in","r",stdin);
- freopen("password.out","w",stdout);
- input();
- work();
- return 0;
- }
Manacher思想 SCOI2013 密码的更多相关文章
- 【BZOJ3325】[Scoi2013]密码 Manacher
[BZOJ3325][Scoi2013]密码 Description Fish是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进. ...
- 【bzoj3325】[Scoi2013]密码 逆模拟Manacher
题目描述 给出一个只包含小写字母的字符串的长度.以每一个字符为中心的最长回文串长度.以及以每两个相邻字符的间隙为中心的最长回文串长度,求满足条件的字典序最小的字符串. 输入 输入由三行组成.第一行仅含 ...
- BZOJ3325 [Scoi2013]密码 【manacher】
题目 Fish是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进.通过翻阅古籍,Fish 得知了这个密码的相关信息: 该密码的长度 ...
- BZOJ 3325 [SCOI2013]密码 (逆模拟Manacher+构造)
题目大意:给你一个字符串每个位置和相邻两个位置为回文中心的最长回文串长度,让你构造一个合法的字典序最小的字符串 挺有意思的构造题 首先按照$Manacher$的思想还原$p$数组 定义$f_{ij}$ ...
- BZOJ3325 [Scoi2013]密码【Manacher】【构造】【贪心】
Description Fish是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进.通过翻阅古籍,Fish 得知了这个密码的相关信 ...
- 2019.03.28 bzoj3325: [Scoi2013]密码(manacher+模拟)
传送门 题意: 现在有一个nnn个小写字母组成的字符串sss. 然后给你nnn个数aia_iai,aia_iai表示以sis_isi为中心的最长回文串串长. 再给你n−1n-1n−1个数bib_ ...
- SCOI2013 密码
题目描述: Fish是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进. 通过翻阅古籍,Fish 得知了这个密码的相关信息: 该密 ...
- luogu P3279 [SCOI2013]密码
LINK:密码 给出来manacher的数组 让还原出字典序最小的字符串.字符集为小写字母. 当没有任何限制时 放字典序最小的'a'.如果此时还在最长的回文串中的话那么 直接得到当前字符即可. 注意这 ...
- BZOJ3325 : [Scoi2013]密码
从以每一位为中心的回文串长度可以用Manacher倒推出$O(n)$对相等和不等关系. 将相等的用并查集维护,不等的连边. 然后输出方案时若还没被染过色,则求一个mex. #include<cs ...
随机推荐
- angular template浅析
在我们浏览的页面中有大的网站,也有中小型网站,类型不同其中的页面也就不同,但是纵观大部分的网页是否有什么相同的地方呢?如果浏览的是一般的门户网站或者是什么小型的页面的话这种感觉就不是很明显,但是如果关 ...
- Vijos1352 NOI2006 最大获利 最小权闭合图
Orz胡伯涛<最小割模型在信息学竞赛中的应用> 建图方法: 设立源点S和汇点T,S和用户(共M个)连边,载流量为满足其要求的获利 T和中转站(共N个)连边,载流量为建立该中转站的费用 每个 ...
- SGU 158.Commuter Train
一道简单题. 火车停的位置不是在整点就是在二分之一点,坐标*2,然后枚举火车停的位置,计算总距离即可. code: #include <iostream> #include <cma ...
- gzip命令
http://www.cnblogs.com/peida/archive/2012/12/06/2804323.html 减 少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时, ...
- JQuery无法获取动态添加的图片宽度问题解决办法
$('.imgUl li,.v_img').click(function(){ var _left = 0; var _top = 0; $('body').append('<div class ...
- Asp.net GridView 72般绝技
快速预览:GridView无代码分页排序GridView选中,编辑,取消,删除GridView正反双向排序GridView和下拉菜单DropDownList结合GridView和CheckBox结合鼠 ...
- dedecms flag标签属性
头条[h] flag='h' 推荐[c] flag='c' 幻灯[f] flag='f' 特荐[a] flag='a' 滚动[s] flag='s' 加粗[b] flag='b' 图片[p] flag ...
- unix-环境高级编程-读书笔记与习题解答-第三篇
第一章 第五节 进程与控制 该小节比较粗略的阐述了unix操作系统中用于进程控制的三个函数,分别为 : fork , exec, waitpid, 其中 exec 有五种变体, 这些变体实现的功能全部 ...
- 使用ToUpperInvariant避免使用ToUpper
ToUpperInvariant使用不依赖于区域性进行转换,而ToUpper则使用了当前线程的CultureInfo,进行转换,所以性能会有所影响,以下为测试: [Test] public void ...
- 概率质量函数:怀孕周期的PMF
__author__ = 'dell' import surveyimport Pmfimport matplotlib.pyplot as pyplot table = survey.Pregnan ...