文章目录

  • 题目描述
  • 解析
  • 代码

题目描述

解析

显然应该要尝试套kmp的板子
关键是如何套
也就是那个判断匹配的条件是什么的问题

本题的关键是当kmp匹配时,匹配位之前的所有位大小关系的顺序都是匹配的,所以我们只需要看当前位即可
考虑对b预处理出3个数组:

id1[i]:[1,i-1]中与i相等的最靠右的数与i的距离
id2[i]:[1,i-1]中比i小的最大的数中最靠右的与i的距离
id3[i]:[1,i-1]中比i大的最小的数中最靠右的与i的距离

(其实不是最靠右也可以啦,只是最靠右容易求)
对于”最靠右“的条件,我们可以先顺序对每个值做一个栈记录这个值出现过的位置,然后逆序求,每次再把自己的值对应的栈弹出一个首元素
“比i小的最大”这样的条件我们可以以值域为关键字建一个双向链表,把一开始就没有的和弹出没有了的值都删除掉,直接找 l 或 r 指针即可

然后就是这个判断。
假设当前A匹配到了[i-j+1,i],B数组匹配到了[1,j]
利用这三个数组,有三个对A失配的条件:

若id1[j]存在且a[i+1-id1[j+1]]!=a[i+1],则失配
若id2[j]存在且a[i+1-id2[j+1]]>=a[i+1],则失配
若id3[j]存在且a[i+1-id3[j+1]]<=a[i+1],则失配

这个画画图还是不难理解的,这是一个充要条件
问题得到解决

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef unsigned long long ull;
const int N = 1e6+100;
const int M=1e7+5;
const int mod=1e9+7;
int n,m;
int s;
int a[N],b[N];
int id1[N],id2[N],id3[N];
vector<int>zhan[N];
int top[N];
int l[N],r[N];
void build(){for(int i=1;i<=s;i++){l[i]=i-1;r[i]=i+1;}l[s+1]=s;r[0]=1;
}
void del(int x){l[r[x]]=l[x];r[l[x]]=r[x];}
int ask(int x,int y){return x<y?x:0;}int p[N];
int ans,st[N];
void solve(){p[1]=0;for(int i=1,j=0;i<=m;i++){while(j&&((ask(id1[j+1],j+1)&&b[i+1-id1[j+1]]!=b[i+1])||(ask(id2[j+1],j+1)&&b[i+1-id2[j+1]]>=b[i+1])||(ask(id3[j+1],j+1)&&b[i+1-id3[j+1]]<=b[i+1]))) j=p[j];if(!((ask(id1[j+1],j+1)&&b[i+1-id1[j+1]]!=b[i+1])||(ask(id2[j+1],j+1)&&b[i+1-id2[j+1]]>=b[i+1])||(ask(id3[j+1],j+1)&&b[i+1-id3[j+1]]<=b[i+1]))) j++;p[i+1]=j;//printf("i=%d p=%d\n",i+1,j);}
}
void kmp(){for(int i=0,j=0;i<=n;i++){while(j&&((ask(id1[j+1],j+1)&&a[i+1-id1[j+1]]!=a[i+1])||(ask(id2[j+1],j+1)&&a[i+1-id2[j+1]]>=a[i+1])||(ask(id3[j+1],j+1)&&a[i+1-id3[j+1]]<=a[i+1]))){//printf("  i+1=%d j=%d %d: %d!=%d? %d: %d>=%d? %d: %d<=%d? \n",i+1,j,ask(id1[j+1],j+1),a[i+1-id1[j+1]],a[i+1],ask(id1[j+1],j+1),a[i+1-id2[j+1]],a[i+1],ask(id2[j+1],j+1),a[i+1-id1[j+1]],a[i+1]);j=p[j];} if(!((ask(id1[j+1],j+1)&&a[i+1-id1[j+1]]!=a[i+1])||(ask(id2[j+1],j+1)&&a[i+1-id2[j+1]]>=a[i+1])||(ask(id3[j+1],j+1)&&a[i+1-id3[j+1]]<=a[i+1]))) j++;//printf("i=%d p=%d\n",i+1,j);if(j==m){st[++ans]=i+1-m+1;j=p[j];}}
}
int main(){scanf("%d%d%d",&n,&m,&s);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=1;i<=m;i++) scanf("%d",&b[i]);for(int i=1;i<=s;i++){zhan[i].push_back(0);//zhan[i][0]=0;}for(int i=1;i<=m;i++){zhan[b[i]].push_back(i);//zhan[b[i]][++top[b[i]]]=i;++top[b[i]];}build();for(int i=1;i<=s;i++){if(!top[i]) del(i);}for(int i=m;i>=1;i--){int x=l[b[i]],y=r[b[i]];if(x) id2[i]=i-zhan[x][top[x]];if(y<=s) id3[i]=i-zhan[y][top[y]];if(!--top[b[i]]) del(b[i]);else id1[i]=i-zhan[b[i]][top[b[i]]];//printf("i=%d id1=%d id2=%d id3=%d\n",i,id1[i],id2[i],id3[i]);}solve();kmp();printf("%d\n",ans);for(int i=1;i<=ans;i++){printf("%d\n",st[i]);}return 0;
}
/*
9 6 10
5 6 2 10 10 7 3 2 9
1 4 4 3 2 16 4 10
3 5 2 7 1 9
3 8 2 10
*/

YBTOJ:字符匹配(KMP)相关推荐

  1. 数据结构 4 字符匹配-KMP算法

    第四章主要介绍的是串,但是串的实现没什么必要,最重要的知识点在于KMP算法的使用,大二时数据结构总结过一次KMP算法,大二时总结的比较细致,链接如下: https://blog.csdn.net/we ...

  2. 基于KMP算法的字符匹配问题

    基于KMP算法的字符匹配问题 反正整个清明都在纠结这玩意-差点我以为下个清明要给自己过了. 至于大体的理解,我就不再多说了(还要画图多麻烦鸭),我参考了以下两个博客,写的真的不错. (原创)详解KMP ...

  3. 字符串匹配KMP算法

    字符串匹配KMP KMP过程其实就是去找下一个更好的状态的过程,省略去了中间穷举的无用过程,直接跳到下一个更好的状态,通过模式串本身的信息,站在模式串的角度来考虑问题 取长的一对 若想让模式串直接从S ...

  4. kmp算法详解php,php中字符串匹配KMP算法实现例子

    KMP算法是一个比较高级的算法了,加了改进了,下面我们来在php中实现KMP算法,希望例子对各位同学会带来帮助哦. kmp算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J. ...

  5. 字符串匹配KMP算法设计C语言,KMP字符串匹配算法笔记

    网上有很多解释KMP算法的文章,A_B_C_ABC的这篇很详细,反复看了好几遍,总算理解了个大概,但是总觉得没那么爽快.其实,一种算法各人有各人的理解方法,找到适合自己理解的才容易记住.下面是我对这个 ...

  6. 字符串匹配 (KMP)

    文章目录 字符串匹配 字符串匹配暴力 kmp算法 next[i]数组的实现 kmp算法实现 kmp模板 字符串匹配 在常见的字符串相关的算法问题中有一种较为常见的是匹配问题,分为单模匹配与多模匹配, ...

  7. 字符串匹配KMP算法的理解(详细)

    1. 引言 本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP,思路混乱导致写也写得混乱.所以一直想找机会重新写下KMP,但苦于一直以来对KMP的理解始终不够,故才迟迟没有修改本文. ...

  8. 字符串匹配 KMP算法

    问题描述:字符串匹配即查找待匹配字符串(模式串)p在主串s中的位置.一般处理这种问题往往采用简单粗暴的方法--暴力匹配法.所谓暴力匹配法,就是对主串s的每一个字符与要匹配的字符串p的每个字符进行逐一匹 ...

  9. 字符串匹配——KMP算法

    字符串匹配--KMP算法 ​ 字符串匹配是计算机编程中最常使用到的基础算法之一.字符串匹配相关的算法很多,Knuth-Morris-Pratt(KMP)算法是最常用的之一.最近在学习KMP算法,学习了 ...

  10. R语言grep函数和grepl函数字符匹配实战

    R语言grep函数和grepl函数字符匹配实战 目录 R语言grep函数和grepl函数字符匹配实战 #基本语法

最新文章

  1. CNN网络泛化能力--Why Deep Nets Generalize?
  2. HTML5中引入JS
  3. 直接将自身代码注入傀儡进程
  4. 统计单词出现的次数并进行排
  5. java map 赋值_java Listmap赋值的问题
  6. (转)Android IPC机制详解
  7. EditText自定义边框和背景
  8. php通过mysqldump数据库备份,mysql使用mysqldump进行数据库备份_MySQL
  9. IntelliJ IDEA安装与JDK 环境变量配置
  10. java超级玛丽代码_java版超级玛丽源代码
  11. android gif图片压缩,10种GIF压缩方法
  12. 深度解读互联网+供应链金融八大模式
  13. BASE16、BASE32、BASE64编码特征及正则匹配
  14. 比较PAFF和MBAFF
  15. 功能测试数据测试之因果图分析方法
  16. 安装mediawiki维基百科
  17. Java 开发flink流/批处理程序
  18. 算法岗位真的需要顶会才能入场吗?
  19. pythontrycatch所有异常状态_python 一篇搞定所有的异常处理
  20. 每日思考第 63 期:物理空间限制精神世界的发展

热门文章

  1. 你的专业 VS 你妈口中你的专业
  2. linux 编写脚本示范,Linux-scripts-简单脚本和脚本的执行
  3. 求职学习笔记|并发编程知识点常见问题总结(一)
  4. oracle中的的instr,Oracle中instr函数使用方法
  5. android动画设置的单位,Kotlin语言入门—实现单位转换,view设置,动画等
  6. c语言求平衡因子,平衡二叉树(AVL树)的基本操作
  7. py2exe for python3_使用Py2Exe for Python3创建自己的exe程序
  8. linux自动应答,08. 创建 ks.cfg自动应答文件
  9. signature=fc89d4352b6699754c14ce282ec75426,Method for Assembly of Nucleic Acid Sequence Data
  10. PyTorch深度学习实践