日度归档:2026年3月19日

狠狠地切割 (Hard Version)

现给你一个长度为 n的序列 a1,,an​和 m个互不相同的整数 b1,,bm​。你需要按照这 m个数对序列 a进行狠狠地切割

具体的,对于一个数字 i[1,n],如果存在一个整数 j[1,m],使得 ai=bj,则将位置 i称为一个切割点。对序列 a中的每一个切割点,我们在这个位置进行一次狠狠地切割。方法是,将该位置的数字去除,然后在这个位置将其左右的序列/片段一分两半。

如果对狠狠地切割的定义有疑问,可以参照「样例 #1」及「样例解释 #1」进行理解。

你需要计算,在进行了所有可能的狠狠地切割后,序列被切割为了多少片段

特别的,如果在切割后,某一段内没有数组,那这一段不可被叫做片段。同样的,如果 1或 n为切割点,其与开头和结尾之间也不存在片段。

如果对片段的概念有疑问,可以参照「样例 #2」及「样例解释 #2」进行理解。

【输入格式】

第一行为两个整数,依次表示序列 a的长度 n和序列 b的长度 m
第二行有 n个整数,第 i个整数表示 ai
第三行有 m个整数,第 i个整数表示 bi

【输出格式】

输出一个整数,代表狠狠地切割后的片段的个数。

【输入输出样例#1】

输入#1

6 2
3 4 3 5 2 6
5 4

输出#1

3

【输入输出样例#2】

输入#2

6 3
3 4 3 5 2 6
3 5 6

输出#2

2

【说明提示】

样例 1 解释

狠狠地切割前,序列 aa

如下所示:343526

3326

3片段 13片段 226片段 3

样例 2 解释

以下我们展示去除之后的序列:

42

这个不是片段4片段 1这个不是片段2片段 2这个不是片段

数据规模与约定

  • 对于 30%的数据,保证 a序列中没有任何元素在 b中出现过。形式化的,i[1,n],j[1,m],aibj
  • 对于 100%的数据,保证 1n,m5×1051018ai,bi1018,序列 b中的元素两两不同。

提示

本题输入规模较大,建议考虑使用较快的读入读出方式。

【解题思路】

先将b序列排序,便于后续查找。然后遍历 a序列,通过二分查找法判断是否在b序列中。存在即分割,循环计数

【代码样例】

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5 * 1e5 + 5;
long long a[MAXN];
long long b[MAXN];
int n, m;

bool isdivide(long long x) {
	auto i = lower_bound(b + 1, b + m + 1, x) - b;
	if (x == b[i]) {
		return true;
	} else {
		return false;
	}
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= m; i++) {
		cin >> b[i];
	}
	sort(b + 1, b + m + 1); //排序
	int t = 0;
	int cnt = 0; //计数
	for (int i = 1; i <= n; i++) {
		if (isdivide(a[i])) {
			if (t > 0) {
				cnt++;
				t = 0;
			}
		} else {
			t++;
		}
	}
	if (t > 0) {
		cnt++;
	}
	cout << cnt << endl;

}