BZOJ

洛谷

求给定串的最长双回文串。

\(n\leq10^5\)。

Manacher:

记\(R_i\)表示以\(i\)位置为结尾的最长回文串长度,\(L_i\)表示以\(i\)开头的最长回文串长度。答案就是\(\max\{R_i+L_{i+1}\}\)。式子可能会有差别,因为Manacher会在里面加字符。当然我们直接只用'#'位置的\(L_i+R_i\)就可以更新答案啦。

Manacher,然后对于位置\(i\),设它的最远延伸距离是\(ex_i\)。

然后用\(i-j\)更新\(L_j,\;j\in[i-ex_i+1,\ i]\),\(j-i\)更新\(R_j,\;j\in[i,i+ex_i-1]\)(注意字符串里加了'#'的)。

显然只需要维护更新它的\(\max\{i\},\min\{i\}\)就可以了,可以用线段树。(当然我懒得去写)

但这个做法显然不够好,考虑能否\(O(1)\)更新,也就是更新一个位置然后递推过来。(表示没想出来= =)

可以啊...更新\(i-j\)这个值,相邻两个位置是相差\(1\)的。而从\(j\)更新到\(i\)位置时,\(i-j\)就\(\leq0\)了。也就是我们只更新\(L_{i-ex_i+1}=\max\{ex_i-1\}\),最后用\(L_j=\max\{L_j,\ L_{j-1}-1\}\)递推即可。\(R\)同理。

这样就\(O(n)\)啦。

当然我们只需要在'#'处统计,所以只更新这些位置即可。

回文树:

对正反串建两次回文树,求出每个位置的最长回文长度就可以了。。


Manacher:

//3360kb	84ms
#include <cstdio>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=2e5+5; int ex[N],L[N],R[N];
char s[N]; int Build()
{
int n=strlen(s+1);
for(int i=n; i; --i) s[i<<1]=s[i], s[(i<<1)-1]='#';
s[0]='!', s[n<<1|1]='#', s[(n<<1)+2]='@';
return n<<1|1;
}
void Manacher(const int n)
{
for(int i=1,id,mx=0; i<=n; ++i)
{
if(i<mx) ex[i]=std::min(ex[2*id-i],mx-i);
else ex[i]=1;
while(s[i-ex[i]]==s[i+ex[i]]) ++ex[i];
if(i+ex[i]>mx) mx=i+ex[i], id=i;
L[i-ex[i]+1]=std::max(L[i-ex[i]+1],ex[i]-1);
R[i+ex[i]-1]=std::max(R[i+ex[i]-1],ex[i]-1);
}
} int main()
{
scanf("%s",s+1);
int n=Build(); Manacher(n);
for(int i=n-2; i>=1; i-=2) R[i]=std::max(R[i],R[i+2]-2);//i>=1 not i!
for(int i=3; i<=n; i+=2) L[i]=std::max(L[i],L[i-2]-2);
int ans=0;
for(int i=1; i<=n; i+=2) if(L[i]&&R[i]) ans=std::max(ans,L[i]+R[i]);//if!
printf("%d\n",ans); return 0;
}

回文树:

//23576kb	156ms
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=1e5+5; char s[N];
struct PAM
{
int las,tot,fail[N],son[N][26],len[N],mx[N]; PAM() {tot=1, fail[0]=1, len[1]=-1;}
inline int Find(int x,int n)
{
while(s[n-len[x]-1]!=s[n]) x=fail[x];
return x;
}
void Insert(int c,int n)
{
int p=Find(las,n);
if(!son[p][c])
{
int np=++tot; fail[np]=son[Find(fail[p],n)][c];
son[p][c]=np, len[np]=len[p]+2;
}
las=son[p][c];
}
void Build(char *s,const int n,const int opt)
{
if(opt) for(int i=1; i<=n; ++i) Insert(s[i]-'a',i), mx[i]=len[las];
else for(int i=1; i<=n; ++i) Insert(s[i]-'a',i), mx[n-i+1]=len[las];//...
}
}p1,p2; int main()
{
scanf("%s",s+1); int n=strlen(s+1);
p1.Build(s,n,1), std::reverse(s+1,s+1+n), p2.Build(s,n,0);
int ans=0;
for(int i=1; i<n; ++i) ans=std::max(ans,p1.mx[i]+p2.mx[i+1]);
printf("%d\n",ans); return 0;
}

BZOJ.2565.[国家集训队]最长双回文串(Manacher/回文树)的更多相关文章

  1. Manacher || P4555 [国家集训队]最长双回文串 || BZOJ 2565: 最长双回文串

    题面:P4555 [国家集训队]最长双回文串 题解:就.就考察马拉车的理解 在原始马拉车的基础上多维护个P[i].Q[i]数组,分别表示以i结尾最长回文子串的长度和以i开头的最长回文子串的长度 然后就 ...

  2. P4555 [国家集训队]最长双回文串

    P4555 [国家集训队]最长双回文串 manacher 用manacher在处理时顺便把以某点开头/结尾的最长回文串的长度也处理掉. 然后枚举. #include<iostream> # ...

  3. 洛谷 P4555 [国家集训队]最长双回文串 解题报告

    P4555 [国家集训队]最长双回文串 题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为\(n\)的串 ...

  4. 【洛谷】P4555 [国家集训队]最长双回文串

    P4555 [国家集训队]最长双回文串 题源:https://www.luogu.com.cn/problem/P4555 原理:Manacher 还真比KMP好理解 解决最长回文串问题 转化为长度为 ...

  5. Manacher【p4555】 [国家集训队]最长双回文串

    题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为 n 的串 S ,求 S 的最长双回文子串 T ,即可 ...

  6. [国家集训队]最长双回文串 manacher

    ---题面--- 题解: 首先有一个直观的想法,如果我们可以求出对于位置i的最长后缀回文串和最长前缀回文串,那么我们枚举分界点然后合并前缀和后缀不就可以得到答案了么? 所以我们的目标就是求出这两个数列 ...

  7. P4555 [国家集训队]最长双回文串(回文树)

    题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为 n 的串 S ,求 S 的最长双回文子串 T ,即可 ...

  8. luoguP4555 [国家集训队]最长双回文串 manacher算法

    不算很难的一道题吧.... 很容易想到枚举断点,之后需要处理出以$i$为开头的最长回文串的长度和以$i$为结尾的最长回文串的长度 分别记为$L[i]$和$R[i]$ 由于求$R[i]$相当于把$L[i ...

  9. 【洛谷 P4555】 [国家集训队]最长双回文串 (Manacher)

    题目链接 \(|S|<=10^5\),时间还是很宽松的. 允许我们使用线性/\(N\log N\)/甚至\(N \sqrt N\)的算法. 设\(l[i]\)表示以\(a[i]\)结尾的最长回文 ...

随机推荐

  1. java String正则表达式

    1.正则表达式 字符串替换,     例子; String s="131hello334thrid  ".replaceAll("[a-zA-Z]"," ...

  2. Nginx详解八:Nginx基础篇之Nginx请求限制的配置语法与原理

    Nginx的请求限制: 连接频率的限制:limit_conn_module 配置语法:limit_conn_zone key zone=name:size;默认状态:-配置方法:http 配置语法:l ...

  3. 属性(property)的特性(attribute)

    属性:对象中可以保存数据的变量 属性的特性:     数据属性的特性(默认值是false):value.writable(可写否) .enumerable(可否枚举).configurable(可否重 ...

  4. druid配置oracle遇到: 未找到要求的 FROM 关键字 errorCode 923, state 42000

    2018年05月29日 16:41:17 阅读数:518 问题背景 项目要连接oracle数据,采用的是durid连接池,但是基本配置下来,运行时发现了这个错误. 方案 可能有的一个错误就是,拼凑sq ...

  5. js 图片转换base64 base64转换为file对象

    function getImgToBase64(url,callback){//将图片转换为Base64 var canvas = document.createElement('canvas'), ...

  6. Expected one result (or null) to be returned by selectOne(), but found: 3

    Expected one result (or null) to be returned by selectOne(), but found: 3 返回应该是对象但是给的是list

  7. The.Glory.of.Innovation 创新之路3放飞好奇

    教育最重要的就是 问题不在于教他各种学问,而在于培养他爱好学问的兴趣,而且在这种兴趣充分增长起来的时候,教他以研究学问的方法. ————  卢梭     如何辨识不同的观点, 老师考查的重点不在于学生 ...

  8. config.GetSection(key)编译不通过

    要安装这个版本

  9. 【C++ Primer | 07】常用算法

    第一部分 常用泛型算法: find(beg, end, val); equal(beg1, end1, beg2); fill(beg, end, val); fill_n(beg, cnt, val ...

  10. Gradle Build速度加快方法汇总

    Android Studio用起来越来越顺手,但是却发现Build的速度实在不敢恭维,在google和度娘了几把(....)之后,大体就是分配更高的内存,步骤:Setting-->搜索gradl ...