本题限制时间1s,而数据范围2e5,也就是说时间复杂度顶多
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)了,那就不能直接暴力枚举,可以使用双指针。
在使用双指针时要思考主要指针指向什么,在什么条件下能够更新另一个指针。
在本题中要找的是最大的友善值,并且要保证期望友善值得到满足,假如现在使得主指针扫描的是每个猫猫,那么另一个指针如果扫到了能达到期望的人,就把友善值取 m a x max max,然后去扫下一个人。
所以要对猫猫进行按照友善值升序排序,对人进行按照期望友善值升序排序,那么就可以实现以下操作:
- 枚举猫的时候是按照友善值升序,扫人的时候是按照期望友善值升序,如果当前猫友善值不如期望值高,那之后的人的期望值会更高,就更不会满足,所以 j j j 就不用再往后扫了,直接停住就可以。
- 过程中一直维护最大的友善值,当前扫到第j个人,取到的友善值是 1 1 1 ~ j j j部分最大的,每扫一个猫猫,猫猫的友善值都会更高,如果当前的猫猫满足了第j个人的期望,那么后面的猫猫一定都满足了。
- j j j 没必要重置回去,因为重置回去只可能导致人的最大的友善值改变,但是往后扫猫猫的期望友善值一定满足前j个,所以 j j j 往回走是完全没必要的
故此题可以进行双指针。
注意:
- 本题求解的时候要求按照原来读入时的顺序输出每个猫猫的答案,所以要确定好原始下标,以保证sort之后输出时不会乱序。
代码: 注:range
代表for循环
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
//a:start b:end c:step
#define range(i,a,b,c) for(int i = a;i <= b;i+=c)
struct Node {
int x, y; //x:友善值,y:期待友善值
int id; //id:读入时候的下标
}cat[N], person[N];
int n, m;
int main() {
cin >> n >> m;
vector<int>ans(n);
//一串读入
range(i, 1, n, 1) cin >> cat[i].x;
range(i, 1, n, 1)cin >> cat[i].y;
range(i, 1, m, 1) cin >> person[i].x;
range(i, 1, m, 1)cin >> person[i].y;
//初始化初始下标
range(i, 1, n, 1)cat[i].id = i;
range(i, 1, m, 1)person[i].id = i;
sort(cat + 1, cat + 1 + n, [=](Node a, Node b) { //猫按照友善值升序排序
return a.x < b.x;
});
sort(person + 1, person + 1 + m, [=](Node a, Node b) { //人按照期望友善值升序排序
return a.y < b.y;
});
int j = 1,MM = -1e9;
range(i,1,n,1) {
//满足猫友善值大于等于人期望友善值的情况下,一直往后扫人
while (cat[i].x >= person[j].y && j <= m) {
MM = max(MM, person[j].x);//更新MM为最大的友善值
j++;//往后扫
}
//友善值大于猫的期望友善值时
if (MM >= cat[i].y) ans[cat[i].id] = MM;
else ans[cat[i].id] = -1;
}
range(i, 1, n, 1) cout << ans[i] << " ";
return 0;
}