~~~题面~~~

题解:

首先有一个直观的想法,如果我们可以求出对于位置i的最长后缀回文串和最长前缀回文串,那么我们枚举分界点然后合并前缀和后缀不就可以得到答案了么?

所以我们的目标就是求出这两个数列,

我们令f[i] 表示以i为结尾的最长回文后缀的长度,g[i]表示以i为开头的最长回文后缀的长度。

由于要找回文串,因此我们先想到manacher。

然后我们可以发现对于这样一个串:

原串:xxxxxxxxxx

新串:#x#x#x#x#x#x#x#x#x#x#

我们可以观察到,假设这时我们已经求出了f和g,那么对于任意位置而言,合并出的最长双回文串中,都是“偶串”,且有一半是'#',一半是原串。

因此我们可以直接合并f[i-1] 和 g[i],并用ans记录最大值,那么这时真正的答案就是ans / 2.

假设我们manacher已经求到了第i位,此时i的最长回文半径是R,且j已经被包括在R里面了,那么显然i对j的贡献是(j - i) * 2 + 1。

而因为贡献只和i与j的位置有关,并且我们的i是从1开始,逐渐递增的,因此对于任意一个j,第一次将它更新的i必然可以产生最优解,因此每个j会且仅会被更新一次。

而被更新的j显然也是递增的,因为如果j后面的k已经被更新的话,说明之前已经有一个i可以使得k被覆盖在内了。那么j既然在k前面,肯定也被覆盖过了,

因此求出f[j]时,j肯定是递增的(也就是说肯定是先求出前面的在求出后面的),因此我们可以直接维护一个指针t(这个指针只是字面上的指针),表示当前已经更新到了t,

一旦被覆盖的MaxRight > t,我们就直接用当前的i来更新t。

对于前缀回文串,我们直接把字符串翻转过来,然后再做一遍相同的操作,再把得到的数组反转回来就可以了

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 202000
/*处理出前缀半径和后缀半径,然后合并。可以发现,在扩充了数列之后(#),
获取的最长双回文串一定是偶串,且# 和 真实字符数量相同。
因此ans就是合并后的最长长度/2*/
int n, pos, maxn, ans;
int f[AC], g[AC], tmp[AC], r[AC];
char s[AC], p[AC]; void pre()//读入
{
scanf("%s", s + );
n = strlen(s + );
for(R i = n; i; --i) s[i * ] = s[i];
n = * n + ;
for(R i = ; i <= n; i += ) s[i] = '#';
for(R i = ; i <= n; i++) p[i] = s[n - i + ];//把原串倒过来做一遍就是后缀了
s[] = p[] = '$', s[n + ] = p[n + ] = '$';
} void build()//处理出前缀半径和后缀半径
{
int t = ;
pos = maxn = ;
for(R i = ; i <= n; i++)
{
r[i] = maxn > i ? min(r[ * pos - i], maxn - i + ) : ;
while(s[i - r[i]] == s[i + r[i]]) ++r[i];
if(i + r[i] - > maxn)
{
maxn = i + r[i] - , pos = i;
if(maxn > t)//更新后缀
{
for(R j = t + ; j <= maxn; j++) f[j] = (j - i) * + ;
t = maxn;
}
}
}
pos = maxn = t = ;
for(R i = ; i <= n; i++)
{
r[i] = maxn > i ? min(r[ * pos - i], maxn - i + ) : ;
while(p[i - r[i]] == p[i + r[i]]) ++r[i];
if(i + r[i] - > maxn)
{
maxn = i + r[i] - , pos = i;
if(maxn > t)//更新后缀
{
for(R j = t + ; j <= maxn; j++) tmp[j] = (j - i) * + ;
t = maxn;
}
}
}
for(R i = ; i <= n; i++) g[i] = tmp[n - i + ];
// for(R i = 1; i <= n; i++) printf("%d ", f[i]);
// printf("\n");
} inline void upmax(int &a, int b)
{
if(b > a) a = b;
} void work()//合并
{
for(R i = ; i <= n; i++)
upmax(ans, f[i - ] + g[i]);
printf("%d\n", ans/);
} int main()
{
freopen("in.in", "r", stdin);
pre();
build();
work();
fclose(stdin);
return ;
}

[国家集训队]最长双回文串 manacher的更多相关文章

  1. BZOJ.2565.[国家集训队]最长双回文串(Manacher/回文树)

    BZOJ 洛谷 求给定串的最长双回文串. \(n\leq10^5\). Manacher: 记\(R_i\)表示以\(i\)位置为结尾的最长回文串长度,\(L_i\)表示以\(i\)开头的最长回文串长 ...

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

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

  3. 洛谷P4555 [国家集训队]最长双回文串(manacher 线段树)

    题意 题目链接 Sol 我的做法比较naive..首先manacher预处理出以每个位置为中心的回文串的长度.然后枚举一个中间位置,现在要考虑的就是能覆盖到i - 1的回文串中 中心最靠左的,和能覆盖 ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. mongoDB在java上面的应用

    1.实际应用过程中肯定不会直接通过Linux的方式来连接和使用数据库,而是通过其他驱动的方式来使用mongoDB 2.本教程只针对于Java来做操作,主要是模拟mongoDB数据库在开发过程中的应用 ...

  2. java操作HDFS

    package com.lei.hadoop; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Fil ...

  3. zedboard学习第一篇

    1. 刚开始学习使用,不知道从哪里开始,手上的资料也很乱,至于这个板子需要学什么也不清楚. 2. 第一个工程就从helloworld开始吧,Zed板上的Zynq是一个PS(processing sys ...

  4. C#中创建二维数组,使用[][]和[,]的区别

    C#中,我们在创建二维数组的时候,一般使用arr[][]的形式,例如 int[][] aInt = new int[2][]; 但声明二维数组还有一种方法,是使用arr[,]的形式.两者有什么区别呢? ...

  5. 142. O(1) Check Power of 2【LintCode by java】

    Description Using O(1) time to check whether an integer n is a power of 2. Example For n=4, return t ...

  6. 树(Tree,UVA 548)

    题目描述: 题目思路: 1.使用数组建树 //递归 2.理解后序遍历和中序遍历,建立左右子树 3.dfs深度搜索找出权重最小的路径 #include <iostream> #include ...

  7. docker学习2

    今天继续学习docker! 搜索镜像 docker search centos 下载镜像 docker pull name(镜像名字) 查看镜像docker images 字段含义分析: TAG:仓库 ...

  8. sql server存储特殊字符解决办法

    好久没来院子了,最近在学java了,再加上项目比较紧,最近都没怎么上,其实这几天在项目中学到不少东西,都能写下来,但是久而久之就忘了,还是得养成及时总结的好习惯啊,还有有时间一定要把那个小项目整理下来 ...

  9. Python3 Tkinter-Spinbox

    1.创建 from tkinter import * root=Tk() Spinbox(root).pack() root.mainloop() 2.参数 from_    最小值 to    最大 ...

  10. 索引值迭代-enumerate

    你想在迭代一个序列的同时跟踪正在被处理的元素索引?内置的enumerate() 函数可以很好的解决这个问题: list_c = ['a', 'b', 'c'] for i, c in enumerat ...