一、 题目:
题目背景
本题与 H1 的题意完全一致,区别仅在数据范围。在语言月赛中不存在 H2 题目,本题仅用于增加公开赛的区分度,并不严格遵循比赛考察范围,请酌情完成。
题目描述
现给你一个长度为 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复制
6 2 3 4 3 5 2 6 5 4
输出 #1复制
3
输入 #2复制
6 3 3 4 3 5 2 6 3 5 6
输出 #2复制
2
样例解释
P8889 [入门赛 #7] 狠狠地切割 (Hard Version) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
数据范围
二、解析
首先我们先明白暴力的做法:将两个序列分别放入两个数组a、b。两个for循环遍历找出a数组与b数组中相同的数进行处理。很明显这个步骤的时间复杂度是O(n*m),根据题目里n、m范围可知肯定是超时了。我们肯定要对这里进行优化。
因为两个序列a,b均是无序的,我们先将两个个序列存入数组,然后用sort函数分别对两个数组进行升序排序。又因为题目规定的片段要与原有序列的顺序相同,所以对于序列a,我们选择用一个存放pair<int,int>的容器来存放序列,其中第一个元素为序列的值,第二个元素为序列索引(从1开始)。这样我们可以对第一个元素按大小排序后,再按索引把序列变回原来的顺序。
而后就是寻找相同的值的过程。这个部分我们可以用双指针的方法。指针i指向a的起点,指针j指向j的起点。当a[i].first==b[j],此时i++,并且我们令a[i].first=0(此处j不自增是因为序列可能会有一样的值,所以还要对序列a检查有没有与b[j]相同的值)。如果a[i].x<b[j],则i++。如果a[i].x>b[j],则j++。这样下来,我们只用了n log2 n的时间复杂度就搞定了标记相同元素的步骤(主要是快排)。
而后就是按照序列a第二个元素的值把序列变回原来的顺序。再计算片段的数量。
三、代码
(代码有些潦草,见谅)
#include<bits/stdc++.h>
#define x first
#define y second
#define int long long
using namespace std;
typedef pair<int,int> pii;
vector<pii> a;
const int N=5e5+10;
int b[N];
int n,m;
bool cmp1(pii a,pii b){
return a.x<b.x;
}
bool cmp2(pii a,pii b){
return a.y<b.y;
}
signed main(){
cin>>n>>m;
for(int i=0;i<n;i++){
int x1;
cin>>x1;
a.push_back({x1,i});
}
for(int i=0;i<m;i++){
cin>>b[i];
}
sort(b,b+m);
sort(a.begin(),a.end(),cmp1);
int i=0,j=0;
while(i<n&&j<m){
if(a[i].x==b[j]){
a[i].x=0;
i++;
}
else if(a[i].x<b[j]){
i++;
}
else j++;
}
sort(a.begin(),a.end(),cmp2);
// for(int i=0;i<n;i++){
// cout<<a[i].x<<" ";
// }
int ans=0;
for(int i=0,j=0;i<n;i++){
if(a[i].x!=0){
ans++;
j=i;
while(a[j].x){
j++;
}
i=j-1;
}
}
cout<<ans;
}
四、总结
第一次写题解,有很多不足之处,希望能指出。