To_Heart—题解——老死不相往来
咯咯咯,鸽
题目描述
马孔多是一个奇怪的小镇,镇上的房子沿着一条河流的南岸而建,而且镇上的居民一辈子都只在自家附近一个固定半径的范围内活动,有些居民永远不会相互接触,即使他们生活一辈子也老死不相往来。
马孔多小镇一共有n座房子,以到镇子的西端的距离算,居民家的位置为p,他们活动的范围为r,请问马孔多小镇一共会有多少对住户之间老死不相往来。
输入格式
第1行:一个数N,表示房子的数量(1 <= N <= 50000)
第2 - N + 1行:每行2个数P, R中间用空格分隔,P表示房子的位置,R表示这家住户的活动范围半径(1 <= P, R <= 10^9)
输出格式
输出共有多少对老死不相往来的住户。
样例
样例输入:
4
1 1
2 1
3 2
4 1
样例输出:
1
思路:
首先,因为题目给的是一个点可以运动的范围,我们就把这个点可以运动到的最左边界以及最右边界给储存下来,再用sort从小到大排序左边界后,我们把每个点所能到达的所有点累加,再用总数减去累加值就是正确答案了。这里有两个地方需要注意一下:
- 如何计算总数?
从样例入手,假设共有4个点,且每个点之间都无法相同,则此时的答案即是我们的方案总数,即:3+2+1=6(因为第一个点到不了三个点,第二个点也到不了三个点,但第一个点已经被计算过了,其余点同理);
2.如何计算每个点能到达的点?
首先,因为我们经过了排序,所以当点i到达不了点j时,它也一定到达不了点(j+1),我们可以利用这一性质进行二分,定义一个mid来确定每个点能到达的最远点,如果此点能到达点mid,则将mid往后二分,否则相反;
代码:
#include <bits/stdc++.h>
using namespace std;
struct zz {
int l, r;
} a[50005];
bool cmp(zz x, zz y) { return x.l < y.l; }
int main() {
int n, m = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
int x, y;
scanf("%d%d", &x, &y);
a[i].l = max(0, x - y);
a[i].r = x + y;
m += i;
}
m -= n; //m为总方案数;
/*for(int i=1;i<=n;i++){
cout<<i<<' ';
cout<<a[i].l<<' '<<a[i].r<<endl;
}*/
sort(a + 1, a + n + 1, cmp);
int sum = 0;
for (int i = 1; i <= n; i++) {
int L = i, R = n;
int ans = 0;
while (L <= R) {
int mid = (L + R) / 2;
if (a[mid].l > a[i].r) {
R = mid - 1;
} else {
L = mid + 1;
ans = mid - i;
// printf("i:%d;L:%d R:%d mid:%d ans:%d\n",i,L,R,mid,ans);
}
}
sum += ans;
}
cout << /*m<<endl<<*/ m - sum << endl;
return 0;
}