CF251A Points on Line 题解 二分

题目链接:http://codeforces.com/problemset/problem/251/A

题目描述

一条直线上有 \(n\) 个点,他们的坐标分别是 \(x_1,x_2, \cdots ,x_n\) 。没有两个点的坐标相同。
你可以从这些点中挑选出三个点,使得三个点的最大距离不超过 \(d\)
请求出满足条件的三个点的方案数。

输入格式

输入的第一行包含两个整数 \(n\)\(d\)\(1 \le n \le 10^5; 1 \le d \le 10^9\) )。
接下来的一行包含 \(n\) 个整数 \(x_1,x_2, \cdots ,x_n\) ,分别表示 \(n\) 个点的坐标,坐标的绝对值不超过 \(10^9\)
输入保证坐标是按照递增顺序给你的。

输出格式

输出你选择三个点并且这三个点的最大距离不超过 \(d\) 的方案总数。

样例输入1

4 3
1 2 3 4

样例输出1

4

样例输入2

4 2
-3 -2 -1 0

样例输出2

2

样例输入3

5 19
1 10 20 30 50

样例输出3

1

【样例解释】
样例1中,任意三个点的组合都满足条件;
样例2中,只有两个组合 {-3, -2, -1} 和 {-2, -1, 0} 满足条件;
样例3中,只有一个组合 {1, 10, 20} 满足条件。
【样例分析】
这道题目涉及的算法:二分。
首先我们遍历 \(i\) ,我们设 \(x_i\) 是我们挑选的组合中的第1个元素,
那么我们可以用二分快速找出 \(x\) 中最大的那个满足 \(xj-xi \ge d\) 的坐标 \(j\)
那么 \(x_i\)\(x_j\) 中,除了 \(x_i\) ,我们需要找出挑选任意两个数的组合,就是 \((j-i) \times (j-i-1)/2\) ,将其加到答案中。
最终循环一遍之后输出答案即可。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;

int n;
long long ans, d, a[maxn];

int main() {
    cin >> n >> d;
    for (int i = 0; i < n; i ++) cin >> a[i];
    for (int i = 0; i < n; i ++) {
        int j = upper_bound(a, a+n, a[i]+d) - a - 1;
        long long m = j - i;
        ans += m * (m-1) / 2LL;
    }
    cout << ans << endl;
    return 0;
}
posted @ 2020-01-18 13:54  quanjun  阅读(127)  评论(0编辑  收藏  举报