[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/ 题意分析: 定义两个新字符规则,'?'代表任意一个字符,’*‘代表任意长度的任意字符.输入 ...
随机推荐
- 泛型模板化设计DEMO
泛型模板化设计DEMO 1. 定义Result泛型类 package com.example.core.mydemo.java.fanxing; public class Result<T> ...
- CentOS7学习笔记(三) 用户和用户组管理
用户管理 Linux中root用户是权限最大的用户,一般情况下只有服务器管理员拥有root用户的使用权,而我们会使用其他用户来连接Linux 创建用户的命令 创建用户的命令是useradd name, ...
- 如何更改.NET中的默认时区?
除了"在操作系统中修改时区信息,然后重启.NET应用程序,使其生效"之外.如何在不修改操作系统时区的前提下,修改.NET中的默认时区呢? 这是一位 同学兼同事 于5月21日在技术群 ...
- git 删除远程分支文件
问题:多人协作开发同一分支的时候,有人误上传了一个不需要的文件,想删除远端仓库的该文件. 本地已经将此文件删除,推送至仓库时,仓库并未删除.此时拉取仓库更新本地时也不会将此文件拉取下来. 解决方案: ...
- 数据库学习(一)——DDL数据库定义语句
定义数据库 创建数据库 使用CRETE DATABASE关键字,指定编码和排序格式 CREATE DATABASE mysqldb DEFAULT CHARACTER SET utf-8 DEFAUL ...
- 4.4K Star!推荐一款新一代的极简监控系统!轻量高性能!超500个监控指标,颜值高、功能强大!
在信息化快速发展的今天,企业运维面临的挑战日益增多.传统的运维监控系统往往存在功能冗余.性能低下.操作复杂等问题,难以满足现代企业对高效.稳定.智能的运维管理需求. 今天给大家推荐一款新一代极简运维监 ...
- 3562-IgH EtherCAT主站开发案例
- 使用EF 连接 数据库 SQLserver、MySql 实现 CodeFirst
1.新建项目,下载Nuget安装包 创建项目需要注意几点,如果是基于 .net framework 的项目 需要选择 相应版本的 EF, 如果是跨平台则选择EF Core版本. 我这里选择的是 .ne ...
- github中的子模块(git submodule)
git中支持引用另外一个开源库,并且可以指定依赖的分支或者提交记录号. 比如fltk-rs 库的fltk-sys模块依赖了库 cfltk 并指明了依赖的提交是 8a56507 甚至可以嵌套,毕竟库自身 ...
- [oeasy]python049_帮助手册_pydoc_manual_document
帮助手册 回忆上次内容 上次了解了注释 注释是为了让程序更可读 注释不会影响程序运行速度 注释分为两种 单行的 以#开头 不能是字符串当中的# 多行的 三个" 三个' 多行注 ...