题目链接: 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. [转载]Python print函数用法,print 格式化输出

    使用print输出各型的 字符串 整数 浮点数 出度及精度控制 strHello = 'Hello Python' print strHello #输出结果:Hello Python #直接出字符串 ...

  2. html5 日常小结

    HTML5新标签汇总 1.  html5新的 (input type=类型) 元素 <input type="number" name="quantity" ...

  3. c语言-单链表(一)

    定义节点: typedef struct Node { int data; Node* pNext; }NODE, *PNODE; 细节说明,PNode 就代表struct Node* ,上面的表单是 ...

  4. typescript整合到vue中的详细介绍,ts+vue一梭子

    通过vue-cli命令行安装vue项目,注意不要eslint 安装依赖 cnpm install typescript --save-dev cnpm install ts-loader --save ...

  5. 关于多账套API的设计

    帐套在财务核算中是记载一个独立核算的经济实体的所有往来信息的一整套记录表和统计分析报表.不同的帐套之间的关系是相对独立的,对其中的任何一个帐套中的数据进行建立.删除或修改都不会影响其他帐套.在ERP中 ...

  6. ghld data format

    %CTF: 1.00%FileType: PROF strp "VelocityProfile"%PROFSpec: 1.00 2006 00 00%Manufacturer: C ...

  7. 关于android写入SD卡数据的学习代码

    String path = "data/data/com.example.qqlogin/login.txt"; FileOutputStream fos = new FileOu ...

  8. UIScrollView现实循环滚动

    #import "RootViewController.h" #define width [UIScreen mainScreen].bounds.size.width #defi ...

  9. HDOJ 1164 Eddy's research I

    Problem Description Eddy's interest is very extensive, recently he is interested in prime number. Ed ...

  10. [转载]HTTP的无状态是什么意思?

    文章地址:https://www.cnblogs.com/bellkosmos/p/5237146.html#commentform 作者:赛艇队长 引子: 最近在好好了解http,发现对介绍http ...