前言

题目链接:洛谷

上一题之后,模拟赛又放了一道 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 题解的更多相关文章

  1. 【LOJ#2507】[CEOI2011]Matching(KMP,树状数组)

    [LOJ#2507][CEOI2011]Matching(KMP,树状数组) 题面 LOJ 题解 发现要做的是排名串的匹配. 然后我们考虑把它转成这个位置之前有多少个数小于当前这个数,这样子只要每个位 ...

  2. [LeetCode] Wildcard Matching 题解

    6. Wildcard Matching 题目 Implement wildcard pattern matching with support for '?' and '*'. '?' Matche ...

  3. luoguP4696 [CEOI2011]Matching KMP+树状数组

    可以非常轻易的将题意转化为有多少子串满足排名相同 注意到$KMP$算法只会在当前字符串的某尾添加和删除字符 因此,如果添加和删除后面的字符对于前面的字符没有影响时,我们可以用$KMP$来模糊匹配 对于 ...

  4. LOJ2507 CEOI2011 Matching

    题目链接 参考了 神仙yyb的博客 现在发现kmp不仅能匹配字符串,还可以用于处理任意模式匹配中的状态,如这题中已经匹配的序列中的数的大小关系就是一种状态,使用kmp找到模式序列的每一个前缀的bord ...

  5. O - Matching 题解(状压dp)

    题目链接 题目大意 给你一个方形矩阵mp,边长为n(n<=21) 有n个男生和女生,如果\(mp[i][j]=1\) 代表第i个男生可以和第j个女生配对 问有多少种两两配对的方式,使得所有男生和 ...

  6. LeetCode题解-----Wildcard Matching

    题目描述: '?' Matches any single character. '*' Matches any sequence of characters (including the empty ...

  7. 《LeetBook》leetcode题解(10): Regular Expression Matching——DP解决正则匹配

    我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...

  8. LeetCode题解——Regular Expression Matching

    题目: 正则表达式的匹配,'.'能匹配任何一个字符,'*'之前必须有一个字符,两个结合起来表示之前那个字符出现0到无穷次. 解法: 一定要注意'*'必须结合前面的字符一起使用. 代码: class S ...

  9. [LeetCode]题解(python):010-Regular Expression Matching

    题目来源: https://leetcode.com/problems/regular-expression-matching/ 题意分析: 这道题目定义了两个正则表达式规则.’.’代表任意字符,’* ...

  10. [LeetCode]题解(python):044-Wildcard Matching

    题目来源: https://leetcode.com/problems/wildcard-matching/ 题意分析: 定义两个新字符规则,'?'代表任意一个字符,’*‘代表任意长度的任意字符.输入 ...

随机推荐

  1. com.netflix.hystrix.exception.HystrixBadRequestException: null

    com.netflix.hystrix.exception.HystrixBadRequestException: null 排查方法:如果有多个feign接口的调用,可以在每个调用的方法加上try- ...

  2. 行为型模式(Behavioer Pattern)

    行为型设计模式 行为型模式定义了系统中对象之间的交互与通信,研究系统在运行时对象之间的相互通信与协作,进一步明确对象的职责,包括对系统中较为复杂的流程的控制. 在软件系统运行时对象并不是孤立存在的,它 ...

  3. MySql用户与权限控制

    MySql用户与权限控制 -- 刷新权限命令 # -- 刷新mysql权限命令 flush privileges; 用户管理 1.查看用户 #查看用户 USE mysql; SELECT host,u ...

  4. 详解Web应用安全系列(3)失效的身份认证

    大多数身份和访问管理系统的设计和实现,普遍存在身份认证失效的问题.会话管理是身份验证和访问控制的基础,并且存在于所有有状态的应用程序中.攻击者可以使用指南手册来检测失效的身份认证,但通常会关注密码转储 ...

  5. P6623 [省选联考 2020 A 卷] 树

    day2t2但难度不大,和AGC044C解法类似 题目大意: 给定一棵 \(n\) 个结点的有根树 \(T\),结点从 \(1\) 开始编号,根结点为 \(1\) 号结点,每个结点有一个正整数权值 \ ...

  6. Excel 更改数据同步更新到Mysql数据库

    刚上班,领导给我提出一个需求,想要每天更新Mysql数据库中的原有商品订单状态,添加新的商品订单状态.因为公司目前的数据库只能添加数据,不能更改数据,想要更改原有的数据,只能将原有的数据清空,再导入新 ...

  7. node.js 增删改查(原始)

    index.js  连接数据库 const mongoose = require('mongoose') //数据库连接27017是mongodb数据库的默认端口 mongoose.connect(' ...

  8. java 高效递归查询树 find_in_set 处理递归树

    建表语句 DROP TABLE IF EXISTS `sys_dept`; CREATE TABLE `sys_dept` ( `id` bigint(20) NOT NULL AUTO_INCREM ...

  9. php.ini文件与php.d

    `php.ini` 是 PHP 的主要配置文件,用于全局配置 PHP 的行为和功能.它包含了许多 PHP 的核心设置,如内存限制.错误报告级别.扩展加载等. `php.ini` 文件通常位于 PHP ...

  10. Activity活动生命相关

    启动与结束 页面跳转: startActivity(new Intent(this,xxxx.class)); 关闭当前界面返回上一界面 finish(); //这里我在使用finish遇到一个问题, ...