关于$\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 密码的更多相关文章

  1. 【BZOJ3325】[Scoi2013]密码 Manacher

    [BZOJ3325][Scoi2013]密码 Description Fish是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进. ...

  2. 【bzoj3325】[Scoi2013]密码 逆模拟Manacher

    题目描述 给出一个只包含小写字母的字符串的长度.以每一个字符为中心的最长回文串长度.以及以每两个相邻字符的间隙为中心的最长回文串长度,求满足条件的字典序最小的字符串. 输入 输入由三行组成.第一行仅含 ...

  3. BZOJ3325 [Scoi2013]密码 【manacher】

    题目 Fish是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进.通过翻阅古籍,Fish 得知了这个密码的相关信息: 该密码的长度 ...

  4. BZOJ 3325 [SCOI2013]密码 (逆模拟Manacher+构造)

    题目大意:给你一个字符串每个位置和相邻两个位置为回文中心的最长回文串长度,让你构造一个合法的字典序最小的字符串 挺有意思的构造题 首先按照$Manacher$的思想还原$p$数组 定义$f_{ij}$ ...

  5. BZOJ3325 [Scoi2013]密码【Manacher】【构造】【贪心】

    Description Fish是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进.通过翻阅古籍,Fish 得知了这个密码的相关信 ...

  6. 2019.03.28 bzoj3325: [Scoi2013]密码(manacher+模拟)

    传送门 题意: 现在有一个nnn个小写字母组成的字符串sss. 然后给你nnn个数aia_iai​,aia_iai​表示以sis_isi​为中心的最长回文串串长. 再给你n−1n-1n−1个数bib_ ...

  7. SCOI2013 密码

    题目描述: Fish是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进. 通过翻阅古籍,Fish 得知了这个密码的相关信息: 该密 ...

  8. luogu P3279 [SCOI2013]密码

    LINK:密码 给出来manacher的数组 让还原出字典序最小的字符串.字符集为小写字母. 当没有任何限制时 放字典序最小的'a'.如果此时还在最长的回文串中的话那么 直接得到当前字符即可. 注意这 ...

  9. BZOJ3325 : [Scoi2013]密码

    从以每一位为中心的回文串长度可以用Manacher倒推出$O(n)$对相等和不等关系. 将相等的用并查集维护,不等的连边. 然后输出方案时若还没被染过色,则求一个mex. #include<cs ...

随机推荐

  1. [转]mysql导入导出数据中文乱码解决方法小结

    本文章总结了mysql导入导出数据中文乱码解决方法,出现中文乱码一般情况是导入导入时编码的设置问题,我们只要把编码调整一致即可解决此方法,下面是搜索到的一些方法总结,方便需要的朋友. linux系统中 ...

  2. java中的继承要点

    java的一大特性既是:继承. 1.因为有了一个子类继承了一个父类,才有了后面的多态. 2.类的继承,不要为了节省代码,为了继承而继承,把那个没有任何相关的类链接在一起,继承必须用在 is a,就是例 ...

  3. 330. Patching Array--Avota

    问题描述: Given a sorted positive integer array nums and an integer n, add/patch elements to the array s ...

  4. jQuery慢慢啃之事件(七)

    1.ready(fn)//当DOM载入就绪可以查询及操纵时绑定一个要执行的函数. $(document).ready(function(){ // 在这里写你的代码...}); 使用 $(docume ...

  5. 关于javascript延迟加载图片

    今天在技术群中,有位童鞋问起了javascript延迟加载图片的问题,我在这就给大家说明下原理和实现方法. 延迟加载是通过自定义属性,把真实的img地址存到自定义属性中,如data-url=”img” ...

  6. php && 逻辑与运算符使用说明

    例子:!defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc()); o(︶︿︶ ...

  7. JS 导出图片,toDataURL

    //输出图片 function exportCanvasAsPNG(id, fileName) { //获取canvas元素 var canvasElement = document.getEleme ...

  8. VS2010与VAssistX

    http://www.cnblogs.com/9tian/archive/2011/07/01/2095202.html 最近越来越觉得VAssistX好用,可能是以前没有去仔细研究过吧,也可能是因为 ...

  9. 转:PHP如何阻止用户上传成人照片或者裸照

    原文来自于:http://www.hackbase.com/tech/2014-10-12/69367.html 当前,网络淫秽色情信息屡禁不止.屡打不绝,严重危害未成年人身心健康,严重败坏社会风气, ...

  10. Node.js流

    什么是流? 流是可以从一个源读取或写入数据到连续的目标对象.在Node.js,有四种类型的数据流. Readable - 其是用于读操作. Writable - 用在写操作. Duplex - 其可以 ...