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,求模式串是否在源字符串中出现 最简单的方法就是遍历源 ...
随机推荐
- Java基础--单例类创建和测试
单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在.单例模式有很多好处,它能够避免实例对象的重复创建,不仅可以减少每次创建对象的时间开销,还可以节约内存空间:能够避免由于操作多个实例导致 ...
- bash的使用
转自:http://blog.csdn.net/y2888886/article/details/50535033 在上篇博文的基础上做如下修改 注意一些常见命令中间就要加 “ ” ,否则很多命令无法 ...
- MongoDB优化之一:常见优化方法
常用性能优化方案 创建索引 限定返回结果数 只查询使用到的字段 采用capped collection 采用Server Side Code Execution 使用Hint,强制使用索引 Hint ...
- C Primer Plus学习笔记(六)- C 控制语句:分支和跳转
if 语句: if 语句被称为分支语句(branching statement)或选择语句(selection statement) if 语句的通用形式: if (expression) state ...
- leetcode429
这道题目是属于树的层次遍历,使用两层的队列非空判断. class Solution { public: vector<vector<int>> levelOrder(Node* ...
- 1.《Spring学习笔记-MVC》系列文章,讲解返回json数据的文章共有3篇,分别为:
转自:https://www.cnblogs.com/ssslinppp/p/4528892.html [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://w ...
- elasticsearch(5) curl 操作elasticsearch
创建索引之前可以对索引做初始化操作, 比如指定shards数量以及replicas的数量. library为索引的名称 CURL -XPUT 'http://192.168.1.10:9200 ...
- Excel向数据库插入数据和数据库向Excel导出数据
为了熟悉java里工作簿的相关知识点,所以找了“Excel向数据库插入数据和数据库向Excel导出数据”的功能来实现. 注意事项:1,mysql数据库: 2,需要导入的jar包有 jxl.jar,my ...
- sql server导入excel等数据
1.首先打开并登陆sql server数据库 2.选择要将表导入的数据库,右击选择任务-->导入数据 3.在弹出的窗口中选择下一步 4.在弹出的窗口中选择数据源,也就是从哪种文件导入,sql s ...
- HTML5 学习指导
HTML 语义 HTML5为我们提供了很多旨在精确描述内容的语义元素.确保你可以从它丰富的词汇中获益. <!-- bad --> <div id="main"&g ...