当前位置: 首页 > news >正文

【扩展KMP】P10634 BZOJ2372 music |省选-

本文涉及知识点

较难理解的字符串查找算法KMP

标题

P10634 BZOJ2372 music

题目描述

最近 A、B 两国发生了一场战争。dick 作为 A 国的军事总指挥,最近非常头痛于己方的情报问题。因为 B 国最近雇佣了 Easy 这一位密码专家来给他们的所有通讯加密。

Easy 非常喜欢唱歌,于是他决定将所有的信号都变成旋律储存起来,比如说 11556654433221 11556654433221 11556654433221 就可能是一段加过密的音符,我们用一个等长度的序列来表示它,就变成了 1 , 1 , 5 , 5 , 6 , 6 , … 1,1,5,5,6,6,\dots 1,1,5,5,6,6,。为了增加密码的保密性,他把加密的乐谱又调整了一下,把某些音调改变了,将原序列 A A A 变成 B B B,有 ∣ A ∣ = ∣ B ∣ |A|=|B| A=B,且对于 a i = a j a_i=a_j ai=aj b i = b j b_i=b_j bi=bj,对于 a i < a j a_i<a_j ai<aj b i < b j b_i<b_j bi<bj,对于 a i > a j a_i>a_j ai>aj b i > b j b_i>b_j bi>bj。例如:1122155775 就可能代表了同一段音符。

最近,dick 截获了一段信号,这段信号中可能包含了某些重要信息。根据以往的经验,dick 已经知道了某些旋律所代表的意义。于是 dick 想知道,对于一段已知的旋律,能不能判断它是否在这段截获的旋律中出现?如果出现了,能否找出它出现的次数及位置呢?

「任务」判断给定旋律在截获旋律中出现的次数及位置。

输入格式

第一行三个正整数 n , m , s n,m,s n,m,s n n n 是截获旋律的长度, m m m 是已知旋律的长度,所有的旋律都是 1 ∼ s ( s ≤ 25 ) 1\sim s(s\leq 25) 1s(s25) 的正整数。

接下来 n n n 行,每行一个整数描述截获的旋律 A A A

接下来 m m m 行,每行一个整数描述已知的旋律 B B B

输出格式

第一行一个整数 t t t 表示出现的次数。

然后 t t t 行,按照从小到大给出出现时的起始位置 p p p,即: A [ p … p + m − 1 ] A[p\dots p+m-1] A[pp+m1] 等价于 B B B

输入输出样例 #1

输入 #1

9 6 10
5
6
2
10
10
7
3
2
9
1
4
4
3
2
1

输出 #1

1
3

说明/提示

对于所有数据,保证 1 ≤ n ≤ 1 0 5 1\leq n \leq 10^5 1n105 1 ≤ m ≤ 25000 1\leq m \leq 25000 1m25000

扩展KMP

一,将B离散化,最小的数字改成字符a,次小的数字改成b ⋯ \cdots 。创建字符串26个字符串bb,如果b[j]=‘a’+i,则bb[i][j]=‘1’;否则bb[i][j]=0。
二,pos[i]记录B中’a’+i第一次出现的下标。
三,类似bb,根据a创建26个字符串aa。
四,判断a[i…i + m - 1]是否等效于b的逻辑
一,判断相等的是否相等。aa[i + pos[k]][i…i + m - 1]和bb[k]是否相等。利用z函数。ba[i][j] = bb[i] + aa[j] * *空间复杂度 * *:O((n + m)26 * 26)
二,判断大小关系。a[i + pos[k]] < a[i + pos[k + 1]]。
时间复杂度:O(ss(n+m))

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>#include <bitset>
using namespace std;template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {in >> pr.first >> pr.second;return in;
}template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t);return in;
}template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);return in;
}template<class T = int>
vector<T> Read() {int n;cin >> n;vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}
template<class T = int>
vector<T> ReadNotNum() {vector<T> ret;T tmp;while (cin >> tmp) {ret.emplace_back(tmp);if ('\n' == cin.get()) { break; }}return ret;
}template<class T = int>
vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}class KMPEx
{
public:template<class T>static vector<int> ZFunction(const T* p, int n) {vector<int> z(n);z[0] = n;for (int i = 1, left = 0, r = 0; i < n; ++i) {if (i <= r) {//如果此if,r-i+1可能为负数z[i] = min(z[i - left], r - i + 1);}while ((i + z[i] < n) && (p[z[i]] == p[i + z[i]])) {z[i]++;}if (i + z[i] - 1 > r) left = i, r = i + z[i] - 1;}return z;//z[i] 表示S与其后缀S[i,n]的最长公共前缀(LCP)的长度}static vector<int> ZFunction(string s) {return ZFunction(s.c_str(), s.length());}static int MinCyc(const string& str, int unit = 1) {const int N = str.length();auto z = ZFunction(str);auto Is = [&](int k) {for (int i = k; i < N; i <<= 1) {if (z[i] < min(N - i, i)) { return false; }}return true;};for (int k = unit; k < N; k += unit) { if (Is(k))return k; }return N;}};class Solution {
public:vector<int> Ans(const int N, const int M, const int S, vector<int>& A, vector<int>& B) {const int N2 = unordered_set<int>(B.begin(), B.end()).size();vector<int> bfirst;{vector<vector<int>> binxs(S + 1);for (int i = 0; i < M; i++) {binxs[B[i]].emplace_back(i);}for (const auto& v : binxs) {if (v.size()) { bfirst.emplace_back(v[0]); }}}vector<int> z[26][26];for (int i = 1; i < 26; i++)for (int j : bfirst) {string s(M - j + N, ' ');for (int k = j; k < M; k++) {if (B[k] == B[j]) { s[k - j] = '*'; }}for (int k = 0; k < N; k++) {if (A[k] == i) { s[M + k - j] = '*'; }}z[B[j]][i] = KMPEx::ZFunction(s);}auto Is = [&](int p) {for (int i = 1; i < bfirst.size(); i++) {if (A[p + bfirst[i - 1]] >= A[p + bfirst[i]]) { return false; }}for (auto& j : bfirst) {if (z[B[j]][A[p + j]][p + j + (M - j)] < (M - j)) { return false; }}return true;};vector<int> ans;for (int p = 0; p + M <= N; p++) {if (Is(p)) { ans.emplace_back(p + 1); }}return ans;}
};int main() {
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG	ios::sync_with_stdio(0); cin.tie(nullptr);int N,M,S;	cin >> N >> M >> S;	auto A = Read<int>(N);auto B = Read<int>(M);
#ifdef _DEBUG		printf("N=%d,M=%d,S=%d", N,M,S);Out(A, "A=");Out(B, "B=");//Out(strs2, ",strs2=");//Out(que, ",que=");/*Out(que, "que=");*/
#endif // DEBUG		auto res = Solution().Ans(N,M,S,A,B);cout << res.size() << "\n";for (const auto& i : res) {cout << i << "\n";}return 0;
}

单元测试

	int N,M,S;vector<int> A, B;TEST_METHOD(TestMethod01){N = 6, M = 2, S = 2,A = { 1,1,2,2,3,3},B = { 2,2 };auto res = Solution().Ans(N,M,S,A,B);AssertEx({ 1,3,5 }, res);}TEST_METHOD(TestMethod02){N = 6, M = 2, S = 2, A = { 1,1,3,3,2,2 }, B = { 1,2 };auto res = Solution().Ans(N, M, S, A, B);AssertEx({ 2 }, res);}TEST_METHOD(TestMethod03){N = 6, M = 2, S = 3, A = { 1,1,3,3,2,2 }, B = { 3,1 };auto res = Solution().Ans(N, M, S, A, B);AssertEx({4 }, res);}TEST_METHOD(TestMethod11){N = 9, M = 6, S = 10, A = { 5,6,2,10,10,7,3,2,9 }, B = { 1,4,4,3,2,1 };auto res = Solution().Ans(N, M, S, A, B);AssertEx({ 3 }, res);}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。


http://www.mrgr.cn/news/97638.html

相关文章:

  • C++进阶笔记第二篇:引用
  • 智能设备运行监控系统
  • FreeRTOS临界区
  • CentOS8.5 安装 LLaMA-Factory
  • openEuler24.03 LTS下安装Flink
  • 查看手机在线状态,保障设备安全运行
  • SpringDoc【使用详解】
  • Dev C++下载及安装
  • fpga系列 HDL:跨时钟域同步 4-phase handshake(四相握手通信协议,请求-确认机制)浅释与代码实现
  • 嵌入式---加速度计
  • 搭建hadoop集群模式并运行
  • SearXNG
  • MCP基础学习一:MCP概述与基础
  • Linux 性能调优之CPU调优认知
  • 【回眸】Linux 内核 (十三)进程间通讯 之 共享内存
  • QML Loader:动态加载与控件创建
  • MCP-Playwright: 赋予AI模型操控浏览器的能力
  • c# 数据结构 链表篇 有关单链表的一切
  • 力扣hot100_回溯(2)_python版本
  • Wideband Sparse Reconstruction for Scanning Radar论文阅读