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从小到大排序左边界后,我们把每个点所能到达的所有点累加,再用总数减去累加值就是正确答案了。这里有两个地方需要注意一下:

  1. 如何计算总数?
    从样例入手,假设共有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;
}
posted @ 2020-09-01 23:01  To_Heart  阅读(59)  评论(0编辑  收藏  举报