[CEOI2011] Matching 题解
前言
题目链接:洛谷。
在上一题之后,模拟赛又放了一道 KMP 重定义相等的问题,但是寄了,故再记之。
题意简述
现在给出 \(1 \sim n\) 的排列 \(p\) 和序列 \(h_1, h_2, \cdots, h_m\),请你求出哪些 \(h\) 的子串符合排列 \(p\)。串 \(a_i\) 符合一个排列被定义为其从小到大排序后得到 \(a_{p_i}\)。
题目分析
先想到定义 \(b_{p_i} = i\),那么一个串符合 \(p\),等价于其每个值的排名与 \(b_i\) 相等。
也是考虑,用相对信息来进行匹配。很容易想到,如果对于两个串,每个位置的前驱后继都相等,这两个串是符合上述“符合”的定义的。因为每个数都能够确定在排名中唯一的位置。
由于 KMP 匹配的过程是从左往右扫的过程,我们如果要记相对信息,只能记这个位置和之前位置的相对关系。这是对于 KMP 重定义匹配普遍的结论。这是为什么呢?

比如,之前我们有一个位置和后面的相对信息超出了当前匹配的范围,我们当做它不存在。但是,随着我们向右扫描的过程中,这个位置可能有被包含了进来,就有可能不符合要求。相反,如果我们记录左边的信息,如果超出范围,就不可能再被包含进来,所以不会出现以上情况。
那我们如何设计新的信息呢?我们假设之前匹配到的位置都暂时符合排名关系,那要新增一个值,让这个值也符合排名位置。这是一个类似于在一个有序的数列里面插入一个值,使得这个值插入的位置满足给出的信息。想到,对于 \(b\) 可以预处理出 \(L_i\) 和 \(R_i\) 分别表示 \(i\) 与在 \(1 \sim i - 1\) 中的前驱后继之差。这也和我们要插进去的位置相关。
所以,假设当前位置为 \(i\),\(i - 1\) 匹配到的位置为 \(j\),我们只需要判断 \(S[i - L[j + 1]] < S[i] < S[i + R[j + 1]]\) 就表示可以插到对应位置,满足要求。当然,如果 \(L[j + 1]\) 或 \(R[j + 1]\) 不存在则无需判断。
至于预处理 \(L\) 和 \(R\),由于 \(b\) 是排列,所以倒序枚举,链表查前驱后继并删去当前数即可。
时间复杂度为 \(\Theta(n + m)\)。
代码
略去了快读快写,是最优解。
// #pragma GCC optimize(3)
// #pragma GCC optimize("Ofast", "inline", "-ffast-math")
// #pragma GCC target("avx", "sse2", "sse3", "sse4", "mmx")
#include <cstdio>
using namespace std;
int n, m;
int xym[1000010], yzh[1000010];
int whr[1000010], fail[1000010];
int L[1000010], R[1000010];
int pre[1000010], nxt[1000010];
int ans[1000010], tot;
inline bool check(int *yzh, int x, int y) {
return (!L[x] || yzh[y + L[x]] < yzh[y]) && (!R[x] || yzh[y + R[x]] > yzh[y]);
}
signed main() {
fread(buf, 1, MAX, stdin), read(n), read(m);
for (int i = 1; i <= n; ++i) {
read(whr[i]), xym[whr[i]] = i;
pre[i] = i - 1, nxt[i] = i + 1;
}
for (int i = n; i; --i) {
if (pre[xym[i]] ) L[i] = whr[pre[xym[i]]] - i;
if (nxt[xym[i]] <= n) R[i] = whr[nxt[xym[i]]] - i;
pre[nxt[xym[i]]] = pre[xym[i]];
nxt[pre[xym[i]]] = nxt[xym[i]];
}
for (int i = 1, j = fail[0] = -1; i <= n; ++i) {
while (~j && !check(xym, j + 1, i)) j = fail[j];
fail[i] = ++j;
}
for (int i = 1; i <= m; ++i) read(yzh[i]);
for (int i = 1, j = 0; i <= m; ++i) {
while (~j && (j == n || !check(yzh, j + 1, i))) j = fail[j];
if (++j == n) ans[++tot] = i - n + 1;
}
write(tot), putchar('\n');
for (int i = 1; i <= tot; ++i) write(ans[i]), putchar(' ');
fwrite(obuf, 1, o - obuf, stdout);
return 0;
}
[CEOI2011] Matching 题解的更多相关文章
- 【LOJ#2507】[CEOI2011]Matching(KMP,树状数组)
[LOJ#2507][CEOI2011]Matching(KMP,树状数组) 题面 LOJ 题解 发现要做的是排名串的匹配. 然后我们考虑把它转成这个位置之前有多少个数小于当前这个数,这样子只要每个位 ...
- [LeetCode] Wildcard Matching 题解
6. Wildcard Matching 题目 Implement wildcard pattern matching with support for '?' and '*'. '?' Matche ...
- luoguP4696 [CEOI2011]Matching KMP+树状数组
可以非常轻易的将题意转化为有多少子串满足排名相同 注意到$KMP$算法只会在当前字符串的某尾添加和删除字符 因此,如果添加和删除后面的字符对于前面的字符没有影响时,我们可以用$KMP$来模糊匹配 对于 ...
- LOJ2507 CEOI2011 Matching
题目链接 参考了 神仙yyb的博客 现在发现kmp不仅能匹配字符串,还可以用于处理任意模式匹配中的状态,如这题中已经匹配的序列中的数的大小关系就是一种状态,使用kmp找到模式序列的每一个前缀的bord ...
- O - Matching 题解(状压dp)
题目链接 题目大意 给你一个方形矩阵mp,边长为n(n<=21) 有n个男生和女生,如果\(mp[i][j]=1\) 代表第i个男生可以和第j个女生配对 问有多少种两两配对的方式,使得所有男生和 ...
- LeetCode题解-----Wildcard Matching
题目描述: '?' Matches any single character. '*' Matches any sequence of characters (including the empty ...
- 《LeetBook》leetcode题解(10): Regular Expression Matching——DP解决正则匹配
我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...
- LeetCode题解——Regular Expression Matching
题目: 正则表达式的匹配,'.'能匹配任何一个字符,'*'之前必须有一个字符,两个结合起来表示之前那个字符出现0到无穷次. 解法: 一定要注意'*'必须结合前面的字符一起使用. 代码: class S ...
- [LeetCode]题解(python):010-Regular Expression Matching
题目来源: https://leetcode.com/problems/regular-expression-matching/ 题意分析: 这道题目定义了两个正则表达式规则.’.’代表任意字符,’* ...
- [LeetCode]题解(python):044-Wildcard Matching
题目来源: https://leetcode.com/problems/wildcard-matching/ 题意分析: 定义两个新字符规则,'?'代表任意一个字符,’*‘代表任意长度的任意字符.输入 ...
随机推荐
- 基于阿里Anolis OS8.8 的Hadoop大数据平台建设
基于阿里Anolis OS8.8 的Hadoop大数据平台建设 VNC安装与使用 0 Anolis OS基本操作 0.1 Anolis OS用户与组管理 0.2 系统进程管理 0.3 文件操作命令及权 ...
- apache开源 国内镜像地址
https://mirrors.tuna.tsinghua.edu.cn/apache/kylin/apache-kylin-3.1.1/
- Kotlin 编程语言详解:特点、应用领域及语法教程
什么是 Kotlin? Kotlin 是一种现代.流行的编程语言,由 JetBrains 在 2016 年发布. 自发布以来,它已经变得非常流行,因为它与 Java 兼容(Java 是目前最流行的编程 ...
- 02-Python基础
文件编码 Python2中 在Python2中:默认文件编码是ASC II,所以无法正常输出中文,会报错. 解决办法 在文件的开头添加# -- coding: UTF-8 -- 或者 # coding ...
- 07-Linux文件权限管理
文件的类型 Linux的哲学思想:一切皆文件. Linux的文件分为多种类型. 可以通过ll命令查看文件的类型: ll #输出: -rw-------. 1 root root 1266 2月 29 ...
- Service Mesh Summit 回顾 | 轻舟服务网格的无侵入增强 Istio 经验
在云原生社区近日主办的 Service Mesh Summit 2022 服务网格峰会上,网易数帆云原生技术专家方志恒分享了轻舟服务网格无侵入增强 Istio 的经验,本文据此次分享整理,介绍了对无侵 ...
- webpack4.15.1 学习笔记(一) — 基本概念
目录 入口(entry) 出口(output) 加载器 Loaders 插件 Plugins 模式 webpack.config.js 配置 终终终终于下定决心,对你下手了,系统的学习一下. webp ...
- [oeasy]python0011 - python虚拟机的本质_cpu架构_二进制字节码_汇编语言
程序本质 回忆上次内容 我们把python源文件 词法分析 得到 词流(token stream) 语法分析 得到 抽象语法树(Abstract Syntax Tree) 编译 得到 字节码 (b ...
- 学习笔记--Java方法中的注意事项
Java方法中的注意事项 方法调用 Java的方法在同一个类中调用,可以省略 类名. /* 方法调用 */ public class MethodTest03{ public static void ...
- iOS开发基础142-广告归因
IDFA IDFA是苹果为iOS设备提供的一个唯一标识符,专门用于广告跟踪和相关的营销用途.与之对应的,在Android平台的是谷歌广告ID(Google Advertising ID). IDFA的 ...