NKOJ 4745 选点
NKOJ 4745 选点
暴力
思路
- 暴力枚举第一个、第二个和第三个点判断是否满足要求。
- 暴力枚举第一个点和第三个点,判断是否满足要求。
- 枚举第一个点,将其坐标 \(+d\) 设为 \(x\) ,用循环找最后一个小于等于 \(x\) 的数。
正解
暴力3是最接近正解的方法,实际上找的时候不用循环,因为数组有序,直接用二分。
思路:二分+计数
实现方法
- 对于每一个点,用二分查找最后一个小于等于 \(\text{点坐标}+d\) 的点坐标 \(p\),找到后,中间所有的点都可以选。
- 能选的点共有 \(len=i-p+1\) 个,其中 \(i\) 是当前的点坐标。而选的方案一共有 \(\frac{len \times (len-1)}{2}\) 种,因为每一个点都可以选,选完后能和剩下 \(n-1\) 个点匹配,但要除掉重复的。
代码
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
int n,d,ans=0;
int arr[100005];
signed main(){
scanf("%lld%lld",&n,&d);
for(int i=1;i<=n;i++) scanf("%lld",&arr[i]);
for(int i=1;i<=n;i++){
int p=lower_bound(arr+1,arr+1+n,arr[i]+d)-arr;
if(arr[p]>arr[i]+d||p>n) p--;
int len=i-p+1;
ans+=(len-1)*len/2;
}
printf("%lld",ans);
return 0;
}