跳转至

CF252C_Points on Line

keywords: 双指针

这道题目的题意,是显然的。阅读理解没啥困难,就是找三个点,最大距离不能超过d。然后还友好的告诉你给你的数据是严格递增的,这显然具有单调性,然后看数据范围,好家伙二分走你,或者用尺取法。

img

写一下题解,记录一个细节,主要是没理解为什么那个公式是 ��2

首先给出正式代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

int a[N], n, d;
ll ret;

int main()
{
    cin >> n >> d;
    for (int i = 0; i < n; i++) cin >> a[i];

    int i, j = 0;
    for (i = 0; i + 2 < n; i++){
        while (j < n && a[j] - a[i] <= d) j++;
        if (j - i <= 1) continue;  //i j连在一起无法构成三个点

        ll k = ((j - 1) - i + 1) - 1; //a[i]固定,在其余的点里面Ck2, 任选两个就o了
        ret += k * (k-1) / 2; //Cn2 公式
    }

    cout << ret << '\n';

    return 0;
}

//网上题解并没有准确的说明k是怎么来的,让我数学蒟蒻思考了很久,因为我自己的做法是下面这样的
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

ll n, d, ret;
ll a[N];

int main()
{
    cin >> n >> d;
    for (int i = 0; i < n; i++) cin >> a[i];

    int i, j;
    for (i = 0; i < n-2; i++){
        j = i;
        while (j < n && a[j] - a[i] <= d) j++;

        ll k = j - 1 - i + 1 - 2; 
        ret += k * (k + 1) / 2;  //我这种思考方式,依次固定左端点,枚举右端点,中间点有几种选择,等差求和公式
    }

    cout << ret << '\n';

    return 0;
}

总结:进一步熟悉two pointers,当然二分也是一样的

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

int a[N], n, d;
ll ret;

int main()
{
    cin >> n >> d;
    for (int i = 0; i < n; i++) cin >> a[i];

    for (int i = 0; i + 2 < n; i++){
        int j = upper_bound(a + i, a + n, a[i] + d) - a;
        if (j - i <= 1) continue;

        ll k = ((j - 1) - i + 1) - 1; //a[i]固定,在其余的点里面Ck2, 任选两个就o了
        ret += k * (k-1) / 2; //Cn2 公式
    }

    cout << ret << '\n';

    return 0;
}