ICPC2021南京区域赛 L.Let's Play Curling(二分、思维、构造)
作者:互联网
- 题目:Let's Play Curling
- 题意:给出n个红点,m个蓝点在数轴上,问是否能找到一个实数点c,满足一些红色的点到点c的距离绝对值小于任意的蓝点到点c的绝对值,最多能有几个红色的点能满足该条件,若无则输出Impossible,否则输出能满足该条件红点的个数.
- 解析:实际上就是找出任意两个相邻的蓝点作为左右两个端点能包围几个红点(红点不能在区间端点上),取最大值即可;因为假若蓝点作为区间端点,那该区间的红点里肯定可以找到一个点c满足这个区间所有的红点到点c距离的绝对值小于端点(蓝点)到点c的绝对值.
那么实际上就是找到大于区间左端点的第一个红点位置记为l,找到第一个小于区间右端点的第一个红点的位置记为r,r - l + 1即为答案(结果为0,则找不到满足条件的红点),此处用二分实现即可. - ps:这里比较巧妙的添加两个蓝点:一个蓝点的位置为0,另一个蓝点的位置为一个无穷大的数inf,这样就能保证蓝点可以组合成区间,否则一个蓝点无法组成区间,此外,必须特判找到大于区间左端点的第一个红点的位置是否小于或者等于区间左端点的位置和找到第一个小于区间右端点的第一个红点的位置是否大于或者等于区间右端点的位置,这样则属于非法情况,需要特判;例如red : 3 ,blue:1 2,那当区间右端点为2时,找到的红点必然是3,那此时3不在[1, 2]里,所以为非法情况,相等时候也一样,假如red:1,blue:1,那么此时必然找不到红点满足条件.
- 代码:
#include<iostream>
#include<algorithm>
using namespace std;
#define debug(x) cout << "***" << x << endl
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;
int t;
int n, m;
int a[N], b[N];
int find_min(int k)
{
int l = 1, r = n;
while(l < r)
{
int mid = (l + r + 1) / 2;
if(a[mid] < k) l = mid;
else r = mid - 1;
}
return l;
}
int find_max(int k)
{
int l = 1, r = n;
while(l < r)
{
int mid = (l + r) / 2;
if(a[mid] > k) r = mid;
else l = mid + 1;
}
return l;
}
int main()
{
cin >> t;
while(t --)
{
int res = 0;
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= m; i++) cin >> b[i];
//将红点与蓝点位置从小到大排序
sort(a + 1, a + n + 1);
sort(b + 1, b + m + 1);
b[m+1] = inf; //b[0] = 1, b[m+1] = inf (构造两个特殊蓝点)
for(int i = 0; i <= m; i++)
{
int l = find_max(b[i]); //找到大于区间左端点的第一个红点的位置
int r = find_min(b[i+1]); //和找到第一个小于区间右端点的第一个红点的位置
if(a[l] <= b[i] || a[r] >= b[i+1]) continue; //需要特判保证选出的红色冰壶必须在区间内(不能在区间上)
res = max(res, r - l + 1);
}
if(res) cout << res << endl;
else cout << "Impossible" << endl;
}
return 0;
}
/*
1
2 2
2 2
1 2
*/
标签:ICPC2021,Curling,int,位置,蓝点,Play,端点,区间,红点 来源: https://www.cnblogs.com/K2MnO4/p/14826316.html