[题解] Luogu P5446 [THUPC2018]绿绿和串串
时间:2021-08-29
本文章向大家介绍[题解] Luogu P5446 [THUPC2018]绿绿和串串,主要包括[题解] Luogu P5446 [THUPC2018]绿绿和串串使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
[题解] Luogu P5446 [THUPC2018]绿绿和串串
·题目大意
- 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\),
有\(f(S)= \{S_1,S_2,...,S_{n-1},S_n,S_{n-1},...S_2,S_1 \}\)。 - 现在给定一个长度为\(n\)的字符串\(S^{'}\)表示原字符串\(S\)经过若干次(可能为0)旋转之后的一个前缀,
求原来字符串可能的长度\(l\)。 - 显然当\(l > n\)时一定可行,所以只需要输出所有的\(l\leq n\)即可。
\(|S|\leq 10^6,\Sigma |S| \leq 5 \times 10^6\)
·解题思路
首先想到用 \(Manacher\) 。
由于进行翻转操作后回文串长度必定为奇数,所以不用插入字符,然后考虑什么情况下长度是可行的。
- 我们定义一个 \(flag\) 数组,\(flag[i]\) 表示长度为 \(i\) 时是可行的。回文数组为\(p\),\(p[i]\)表示第 \(i\) 位的回文半径位 \(p[i]\)
- 如果只进行了一次翻转操作即可使得前缀为\(S^{'}\),那么有 \(i + p[i] - 1 == n\)
- 如果需要进行\(k\)次翻转才可以使得前缀为\(S^{'}\),那么有 \(i - p[i] + 1 == 1\),然后可以转化为进行\(k - 1\)次的情况。
但是实际操作中我们不用跑 \(k\) 次,只需要倒着跑并记录 \(flag\) ,因为当我们处理长度为 \(i\) 的时候,\(flag[i + 1]\) 到 \(flag[n]\) 都已经处理过了,所以判断 \(flag[i + p[i] - 1] == 1\)即可。 - 时间复杂度为\(O(n)\)。
代码实现
#include <iostream>
#include <cstring>
using namespace std;
#define reg register
namespace io {
char ch[20];
template<typename T>inline void write(T x) {
(x < 0) && (x =- x, putchar('-'));
(x) || putchar('0');
reg int i = 0;
while (x) ch[i++] = x % 10 ^48, x /= 10;
while (i) putchar(ch[--i]);
}
}//快写
#define wt io::write
const int maxN = 1000010;
char s[maxN];
int p[maxN], flag[maxN];
int n;
void work();
int main() {
int t;
scanf("%d", &t);
while (t--) work();
return 0;
}
void work() {
for (reg int i = 1; i <= n; ++i) flag[i] = p[i] = s[i] = 0;
n = 1; s[0] = '@';
scanf("%s", s + 1);
while (s[n]) ++n;
--n;
for (reg int i = 1, r = 0, mid = 0; i <= n; ++i) {
if (i <= r) p[i] = min(p[mid * 2 - i], r - i + 1);
while (s[i + p[i]] == s[i - p[i]]) ++p[i];
if (i + p[i] - 1 >= r) r = i + p[i] - 1, mid = i;
}//Manacher
for (reg int i = n; i; --i) {
if (i + p[i] - 1 == n || (flag[i + p[i] - 1] && i - p[i] + 1 == 1)) flag[i] = 1;
}//上面说的两种情况
for (reg int i = 1; i <= n; ++i)
if (flag[i]) wt(i), putchar(' ');
putchar('\n');
}
原文地址:https://www.cnblogs.com/LitDarkness/p/15203371.html
- 03.HTML头部/CSS/图像/表格/列表
- 巧用flashback database实现灵活的数据切换(r5笔记第9天)
- 01.HTML教程/简介/基础
- 大型分布式网站架构技术总结
- MySQL和Oracle对比之存储过程(r5笔记第7天)
- 07.Java变量类型
- OAuth 2.0验证【面试+工作】
- MySQL备份恢复第一篇(r5笔记第5天)
- 经典面试问题: Top K 之 -- 海量数据找出现次数最多或,不重复的
- Java多线程详解4【面试+工作】
- Java多线程详解5【面试+工作】
- Java多线程详解6【面试+工作】
- MySQL备份恢复第二篇(r5笔记第6天)
- SpringMVC 中配置 Swagger 插件.
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- FlutterDojo设计之道—状态管理之路(五)
- Python高级进阶(一)Python框架之Django入门
- python 自动化测试(2):针对密码输入框为密码控件时的解决方案
- 微信小程序开发之视图容器swiper
- WINDOWS服务器同时安装多个版本的MYSQL的方法,MQYSQL5和MQYSQL8的共存。
- 使用PHP对接国外的PAYPAL支付最新REST API接口。
- golang 学习(10): 使用go语言调用c语言的so动态库
- Django的form,model自定制
- 排序算法与查找算法
- nginx学习(1): openresty安装
- 2020年8月26日更新WINDOWS服务器同时安装多个版本的MYSQL的方法,MQYSQL5和MQYSQL8的共存。
- python 自动化测试(3):数据库连接与使用
- 微信小程序实战开发二:微信小程序 WEUL组件之 画廊组件
- 关于Cookie和Session
- 微信小程序实战开发一:在小程序中使用useExtendedLib方法引入官方UI