题目链接: http://poj.org/problem?id=3167

题意: 给出两串数字 s1, s2, 求主串 s1 中的 s2 匹配数并输出每个匹配的开头位置. 区间 [l, r] 是 s2 的一个匹配当且仅当 s1[i] 是 [l, r] 中的第 s2[i - l] 大元素, 其中 l <= i <= r.

思路: 首先有个结论, 两个串的排名串相等当且仅当这两个串的每个位置上的元素前面等于它的元素个数和小于它的元素个数都相等. 那么可以先花 s * n + s * m 的时间预处理一下 vis1[i][j] 为 s1 前 i 个数字中有多少个小于等于 j, vis2[i][j] 为 s2 前 i 个数字中有多少个小于等于j. 然后可以用 kmp 匹配即可. 注意一下和一般 kmp 不同的是, 在一般 kmp 中的 s2[i] == s2[j] 和 s1[i] == s2[j] 条件要换成区间 (i - j, i] 中小于等于 s2[i] 的数和区间 [1, j] 中小于等于 s2[j] 的数都相等以及区间 (i - j, i] 中小于等于 s1[i] 的数和区间 [1, j] 中小于等于 s2[j] 的数都相等. 这是由前面那个结论决定的.

代码:

 #include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std; const int MAXN = 1e5 + ;
int n, m, s;
int s1[MAXN], s2[MAXN], nxt[MAXN];
int vis1[MAXN][], vis2[MAXN][], sol[MAXN], tot;
//vis1[i][j]为s1前i个数字中有多少个小于等于j
//vis2[i][j]为s2前i个数字中有多少个小于等于j void init(void){
memset(nxt, , sizeof(nxt));
memset(vis1, , sizeof(vis1));
memset(vis2, , sizeof(vis2));
tot = ;
} void gel(void){
for(int i = ; i <= n; i++){
for(int j = ; j <= s; j++){
vis1[i][j] = vis1[i - ][j];
}
vis1[i][s1[i]]++;
}
for(int i = ; i <= m; i++){
for(int j = ; j <= s; j++){
vis2[i][j] = vis2[i - ][j];
}
vis2[i][s2[i]]++;
}
} void get_nxt(void){
int i = , j = ;
while(i <= m){
int cnt1 = , cnt2 = , cc1 = , cc2 = ;
for(int k = ; k < s2[i]; k++){
cnt1 += vis2[i][k] - vis2[i - j][k]; //累计s2区间(i-j,i]中小于s2[i]的数
}
cc1 = vis2[i][s2[i]] - vis2[i - j][s2[i]]; //s2区间(i-j,i]中等于s2[i]的数
for(int k = ; k < s2[j]; k++){
cnt2 += vis2[j][k]; //累计s2区间[1,j]中小于s2[j]的数
}
cc2 = vis2[j][s2[j]]; //s2区间[1,j]中等于s2[j]的数
if(j == || (cnt1 == cnt2 && cc1 == cc2)) nxt[++i] = ++j;
else j = nxt[j];
}
} void kmp(void){
int i = , j = ;
while(i <= n){
int cnt1 = , cnt2 = , cc1 = , cc2 = ;
for(int k = ; k < s1[i]; k++){ //累计s1区间(i-j,i]中小于s1[i]的数
cnt1 += vis1[i][k] - vis1[i - j][k];
}
cc1 = vis1[i][s1[i]] - vis1[i - j][s1[i]]; //s1区间(i-j,i]中等于s1[i]的数
for(int k = ; k < s2[j]; k++){
cnt2 += vis2[j][k];//累计s2区间[1,j]中小于s2[j]的数
}
cc2 = vis2[j][s2[j]];//s2区间[1,j]中等于s2[j]的数
if(j == || (cnt1 == cnt2 && cc1 == cc2)){
i++;
j++;
}else j = nxt[j];
if(j == m + ){
sol[tot++] = i - j + ;
j = nxt[j];
}
}
} int main(void){
while(~scanf("%d%d%d", &n, &m, &s)){
for(int i = ; i <= n; i++){
scanf("%d", &s1[i]);
}
for(int i = ; i <= m; i++){
scanf("%d", &s2[i]);
}
init();
gel();
get_nxt();
kmp();
printf("%d\n", tot);
for(int i = ; i < tot; i++){
printf("%d\n", sol[i]);
}
}
return ;
}

poj3167(kmp)的更多相关文章

  1. 【POJ 3167】Cow Patterns (KMP+树状数组)

    Cow Patterns Description A particular subgroup of K (1 <= K <= 25,000) of Farmer John's cows l ...

  2. KMP算法求解

    // KMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> using namespac ...

  3. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  4. KMP算法

    KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...

  5. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  6. [KMP]【学习笔记】

    Oulipo Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 36916   Accepted: 14904 Descript ...

  7. KMP算法实现

    链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...

  8. KMP专题

    1.[HDU 3336]Count the string(KMP+dp) 题意:求给定字符串含前缀的数量,如输入字符串abab,前缀是a.ab.aba.abab,在原字符串中出现的次数分别是2.2.1 ...

  9. KMP学习之旅

    说起kmp就要从字符串的匹配说起,下面我们谈谈字符串的匹配 给定一个原字符串:bababababababababb,再给定一个模式串:bababb,求模式串是否在源字符串中出现 最简单的方法就是遍历源 ...

随机推荐

  1. [转载]将网卡(设备中断)绑定到特定CPU

    在前阵子看到HelloDB的一篇文章“MySQL单机多实例方案”中提到: 因为单机运行多个实例,必须对网络进行优化,我们通过多个的IP的方式,将多个MySQL实例绑定在不同的网卡上,从而提高整体的网络 ...

  2. Spring 与 MyBatis 的整合

    本文讨论 Spring 与 MyBatis 的整合. 在 beans.xml 中我们定义了两个 bean: SqlSessionFactoryBean.SqlSessionTemplate. 1.Sq ...

  3. Sass、Less和Stylus

    1.背景介绍 1.Sass背景介绍 Sass是对CSS(层叠样式表)的语法的一种扩充,诞生于2007年,最早也是最成熟的一款CSS预处理器语言,它可以使用变量.常量.嵌套.混 入.函数等功能,可以更有 ...

  4. spring学习十三

    1: RESTful URL : 域和端口 / servlet / 资源 / 参数id 2:  静态资源访问处理? 采用RESTful架构后,需要将web.xml中控制器拦截的请求设置为/,这样会将c ...

  5. 将本地代码上传至github

    注册github账号 https://github.com/ 安装git工具 https://git-for-windows.github.io 1.在github中创建一个项目 2.填写相应信息,点 ...

  6. JS写一个简单的程序,判断年份是平年还是闰年

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. 基于ActiveMQ的Topic的数据同步——初步实现

    一.背景介绍 公司自成立以来,一直以做项目为主,算是经累经验吧,自去年以来,我们部门准备将以前的项目做成产品,大概细分了几个小的产品,部们下面又分了几个团队,分别负责产品的研发,而我们属于平台团队,负 ...

  8. IFC数据模型在三维引擎中模拟

  9. ROS Learning-017 Arduino-For-ROS-002 第一个程序: Hello World

    Arduino For ROS-002 - 第一个程序: Hello World 我的Ubuntu系统:Ubuntu 14.04.10 TLS 32位 Arduino的版本:Arduino 1.6.1 ...

  10. SRA数据转成fastq

    Downloading and installing the SRA Toolkit step1: 下载并安装SRAtoolkit    (Download the Toolkit from the ...