poj3167(kmp)
题目链接: 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)的更多相关文章
- 【POJ 3167】Cow Patterns (KMP+树状数组)
Cow Patterns Description A particular subgroup of K (1 <= K <= 25,000) of Farmer John's cows l ...
- KMP算法求解
// KMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> using namespac ...
- 简单有效的kmp算法
以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...
- KMP算法
KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...
- 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)
前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...
- [KMP]【学习笔记】
Oulipo Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 36916 Accepted: 14904 Descript ...
- KMP算法实现
链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...
- KMP专题
1.[HDU 3336]Count the string(KMP+dp) 题意:求给定字符串含前缀的数量,如输入字符串abab,前缀是a.ab.aba.abab,在原字符串中出现的次数分别是2.2.1 ...
- KMP学习之旅
说起kmp就要从字符串的匹配说起,下面我们谈谈字符串的匹配 给定一个原字符串:bababababababababb,再给定一个模式串:bababb,求模式串是否在源字符串中出现 最简单的方法就是遍历源 ...
随机推荐
- 【转】IMSI和IMEI
国际移动客户识别码(International Mobile Subscriber Identification Number) 为了在无线路径和整个GSM移动通信网上正确地识别某个移动客户,就必须给 ...
- Python使用SMTP模块、email模块发送邮件
一.smtplib模块: 主要通过SMTP类与邮件系统进行交互.使用方法如下: 1.实例化一个SMTP对象: s = smtplib.SMTP(邮件服务地址,端口号) s = smtplib.SMTP ...
- MySQL脚本自动安装mysql-5.6.15-linux-glibc2.5-x86_64.tar.gz
脚本安装mysql-5.6.15-linux-glibc2.5-x86_64.tar.gz 先准备好数据文件的路径 softdir='/data/soft' 把脚本和tar包放在相应的路径下,其实就是 ...
- Spring学习十 rest
1: Web service: 是一个大的概念范畴,它表现了一种设计思想 SOAP 是 Web service 的一个重要组成部份. SOAP 是一种协议而非详细产品.SOAP 是通过 XML ...
- 2.《Spring学习笔记-MVC》系列文章,讲解返回json数据的文章共有3篇,分别为:
转自:https://www.cnblogs.com/ssslinppp/p/4528892.html 个人认为,使用@ResponseBody方式来实现json数据的返回比较方便,推荐使用. 摘要 ...
- oracle常用函数总结(一)
最近在读数据库存储过程,或者在xml里写sql时用到数据库函数,笔者觉得有必要总结一下,当然有的函数笔者也很懵逼,不过可以问度娘啊!好了!开始正题. )s from dual;--1 若nvl第一个参 ...
- DAY7-面向对象之绑定方法与非绑定方法
一.类中定义的函数分成两大类 一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 1. 绑定到类的方法:用classmethod装饰器装饰的方法. 为类量身定制 类.boud_met ...
- Android Fragment用法详解(1)--静态使用Fragment
先说明一下,本例子是运行在Android Studio下面的.同样的代码复制粘贴到Eclipse运行却会报错.具体原因我也没有细查.知道的哥们,留言通知下呗. Fragment,也就是碎片,本意是为了 ...
- css之content
content 属性与 :before 及 :after 伪元素配合使用,来插入生成内容.该属性用于定义元素之前或之后放置的生成内容.默认地,这往往是行内内容,不过该内容创建的框类型可以用属性 dis ...
- python之简单的函数介绍(http://docs.python.org/3/library)
Python不但能非常灵活地定义函数,而且本身内置了很多有用的函数,可以直接调用. 在上面的网站上我们可以进行查询,Python具体都有哪些函数. 我们也可以再交互命令行中来查找函数: >> ...