当前位置: 首页 > news >正文

题解:P3546 [POI 2012] PRE-Prefixuffix

题解:P3546 [POI 2012] PRE-Prefixuffix

题目描述

对于两个串 \(S_1, S_2\),如果能够将 \(S_1\) 的一个后缀移动到开头后变成 \(S_2\),就称 \(S_1\)\(S_2\) 循环相同。例如串 ababba 和串 abbaab 是循环相同的。

给出一个长度为 \(n\) 的串 \(S\),求满足下面条件的最大的 \(L(L\leq \frac n 2)\)\(S\)\(L\) 前缀和 \(S\)\(L\) 后缀是循环相同的。

对于 \(100\%\) 数据,保证 \(1\le n\le 10^6\)

题解

首先可以发现题目需要我们找到 \(S\) 的一种划分方式:\(ABTBA\),最大化 \(|A|+|B|\)。这个问题太难了。

尝试将正向的相等改为反向的相等,即尝试把 border 改成回文串。这两种结构之间有一种对称的关系,由于回文串的结构好,我们有时可以尝试将两个区间的比较改成判定回文串。

这里将 \(S\) 拆为前后两半 \(S_1S_2\),然后分为两个字符串 \(S_1, S_2^R\)(也就是 \(S_2\) 的反串),随后定义两个位置 \(i, j\) “相等”当且仅当 \(S_{1i}=S_{2j}\)\(S_{1j}=S_{2i}\),回文串在此基础上定义。这样,我们就可以改成求两个回文串拼起来的长度了,也就是找 \(i, j\) 使得 \([1,i],[i+1,j]\) 都是回文的。

这里会尝试用 Manacher 维护,但是肯定会有一个问题:这样的“相等”关系不可能具有传递性,Manacher 还是正确的吗?你可以研究一下 Manacher 和它用到的性质并自己模拟一下,这里就不写过程了,就是对的,Manacher 不依赖相等关系的传递性。

那就很爽了,用 Manacher 求出每个位置为中心的最长回文半径,为了求答案我们可能需要维护一下以每个位置开始或结束的最长回文串长度,这是可以线性的,详见下文。然后就做完了,时间复杂度 \(O(n)\)

事实上将 \(S\) 改写为 \(S_1S_nS_2S_{n-1}S_3S_{n-2}\cdots\) 也可以达到和上面一样的效果。

问题:如何求出以每个位置开始或结束的最长回文串长度?(P4555 [国家集训队] 最长双回文串 - 洛谷)

首先还是进行 Manacher 的插入隔板和算法流程求出最长回文半径 \(p_i\)。然后我们令 \(l_i,r_i\) 表示以 \(i\) 为左或右端点的最长回文串长度。根据我对 \(p\) 的定义(要额外 \(-1\)),得到 \(l_{i-p_i+1}\geq p_i-1,r_{i+p_i-1}\geq p_i-1\)。然后还有一个问题就是一个大回文串可以不断删掉两边的字符得到小回文串,所以还有 \(l_i\geq l_{i-2}-2, r_i\geq r_{i+2}-2\)。按顺序 chkmax 就可以了。代码见下文(代码里 \(llen\)\(r\)\(rlen\)\(l\))。

代码实现

#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
constexpr int N = 1e6 + 10;
int n, pal[N], rlen[N], llen[N];
char a[N], b[N];
void manacher() {for (int i = 1, mid = 0, r = 0; i <= n; i++) {if (i <= r) pal[i] = min(pal[mid * 2 - i], r - i + 1);while (a[i - pal[i]] == b[i + pal[i]] && a[i + pal[i]] == b[i - pal[i]]) ++pal[i];if (i + pal[i] - 1 > r) r = i + pal[mid = i] - 1;}
}
int main() {
#ifndef LOCALcin.tie(nullptr)->sync_with_stdio(false);  
#endifcin >> n;for (int i = 1; i <= n / 2; i++) {cin >> a[i * 2];a[i * 2 + 1] = '$';}if (n % 2 == 1) --n, cin >> a[0];for (int i = n / 2; i >= 1; i--) {cin >> b[i * 2];b[i * 2 + 1] = '$';}a[0] = '?', b[0] = '!', a[n + 2] = '*', b[n + 2] = '&', ++n, a[1] = b[1] = '$'; // 注意第一个字符前面也要插板debug("%s\n", a);debug("%s\n", b);manacher();debug(" "); for (int i = 1; i <= n; i++) debug("%d", pal[i]); debug("\n");for (int i = 1; i <= n; i++) rlen[i - pal[i] + 1] = max(rlen[i - pal[i] + 1], pal[i] - 1);for (int i = 3; i <= n; i += 2) rlen[i] = max(rlen[i], rlen[i - 2] - 2); // 这里 += 2 是因为只有这些地方有值for (int i = 1; i <= n; i++) llen[i + pal[i] - 1] = max(llen[i + pal[i] - 1], pal[i] - 1);for (int i = n - 2; i >= 1; i -= 2) llen[i] = max(llen[i], llen[i + 2] - 2);debug(" "); for (int i = 1; i <= n; i++) debug("%d", llen[i]); debug("\n");debug(" "); for (int i = 1; i <= n; i++) debug("%d", rlen[i]); debug("\n");int ans = 0;for (int i = 1; i <= n; i += 2) if (llen[i] == i / 2) ans = max(ans, llen[i] + rlen[i]);cout << ans << endl;return 0;
}
http://www.hskmm.com/?act=detail&tid=296

相关文章:

  • 自然语言处理(NLP)发展脉络
  • 错误报警:“该 CPU 或当前的库版本不支持数据类型”
  • redis各种数据类型
  • 关于 cnpm 的安装
  • 剖析“YOLO”哈希构造的安全隐患与正确替代方案
  • Charles实战秘籍:弱网模拟、Map Local/Remote、HTTPS抓包详解
  • BOE(京东方)“照亮成长路”公益项目走进富平县 科技赋能教育树立可持续发展新标杆
  • 9月23日周二《AI+企业IP获客联盟峰会》,相约东莞厚街富盈酒店
  • 第一次作业 自我介绍+软工5问
  • 深度学习调参新思路:Hyperband早停机制提升搜索效率
  • K8S Ingress 和 Service的作用?
  • Nginx 配置详解:从基础到进阶
  • Nginx 基础
  • 零成本搭建企业系统:五款免费低代码平台推荐
  • 软件工程第一次作业-自我介绍
  • 通过pip的配置文件,来永久设置国内源‌
  • 软工第一次作业
  • .NET 单文件程序详解:从原理到实践 - C#混淆加密大师解包打包单文件程序
  • 用夏普比例和卡玛比率评估基金的性价比
  • 漏洞解析--CSRF
  • 0828-今日热点列表 - jobleap4u.com
  • 第一篇随笔
  • Rust/C/C++ 混合构建 - Buck2构建工具一探究竟
  • CF1404D Game of Pairs
  • Office支持终止:如何防止宏灾难
  • Linux运维-字符处理(1、文件查看)
  • UG NX保姆级下载图文安装教程+激活教程(UG NX 2506安装教程及激活教程)
  • Rust 环境搭建
  • 软件第一次作业
  • Node-RED 究竟是否适合工业场景?