关于$\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. JavaScript HTML DOM 元素(节点)

    JavaScript HTML DOM 元素(节点) 创建新的 HTML 元素 创建新的 HTML 元素 如需向 HTML DOM 添加新元素,您必须首先创建该元素(元素节点),然后向一个已存在的元素 ...

  2. WPF里面的常用笔刷

    程序运行效果 <Window x:Class="This_brush.MainWindow" xmlns="http://schemas.microsoft.com ...

  3. Asp.Net 注册 邮箱激活

    数据库 表的设计 State为用户状态  0为禁用  1为可用  默认为0,下面有个UserGUID,这个字段将来用于激活账户 首先你要写一个表单,验证码神马的,这个我就不写了..直接写处理的 代码在 ...

  4. 算法的优化(C语言描述)

    算法的优化 算法的优化分为全局优化和局部优化两个层次.全局优化也称为结构优化,主要是从基本控制结构优化.算法.数据结构的选择上考虑:局部优化即为代码优化,包括使用尽量小的数据类型.优化表达式.优化赋值 ...

  5. OC 字符和日期的互转

    需要用到NSDateFormatter这个类. 1.字符串转换为日期 [plain]NSDateFormatter* dateFormat = [[NSDateFormatter alloc] ini ...

  6. JSP中用include标签动态引入其它文件报错

    <jsp:include page="<%=path %>/include.jsp"></jsp:include> 报错:attribute f ...

  7. 一个基于nodejs,支持http/https的中间人(MITM)代理,便于渗透测试和开发调试。

    源码地址:https://github.com/wuchangming/node-mitmproxy node-mitmproxy node-mitmproxy是一个基于nodejs,支持http/h ...

  8. .htaccess内容

    <IfModule mod_rewrite.c> Options +FollowSymlinks RewriteEngine On RewriteCond %{REQUEST_FILENA ...

  9. 如何将eclipse里的项目发布到github

    首先,给eclipse安装上EGit 在“Help > Install new software”中添加 http://download.eclipse.org/egit/updates 两个都 ...

  10. unix 环境高级编程 读书笔记与习题解答第四篇

    第一章 第六节 第一小节 这一章没有程序设计和API方面的深入学习,而是注重介绍了unix操作系统中的原始数据类型和系统原型函数,错误处理方面的知识. ____unistd.h____ 该文件包含了u ...