专栏文章

题解:P1296 奶牛的耳语

P1296题解参与者 5已保存评论 5

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
5 条
当前快照
1 份
快照标识符
@mipb1kjg
此快照首次捕获于
2025/12/03 09:04
3 个月前
此快照最后确认于
2025/12/03 09:04
3 个月前
查看原文

前言

在我和好友 UCPP 的热血沸腾的组合技之后,这道题所有题解都被我们叉了,所以抓紧补一篇题解。

题解

先来想暴力做法,再考虑如何优化。
暴力做法非常简单,枚举每一对奶牛(记作奶牛 ii 和奶牛 jj),只要比较这两头奶牛的距离 pipj\left | p_i-p_j \right |dd 的大小即可。时间复杂度 O(n2)O(n^2),显然超时。
考虑优化。我们发现,在我们对 pp 数组排序后,对于每头奶牛(记作奶牛 ii),它后面的所有奶牛离它的距离 pjpi(i<jn)p_j-p_i(i<j \le n) 肯定是逐渐增加的。换而言之,对于每头奶牛 ii,我们只要找出满足 i<jni <j \le npjpidp_j-p_i\le djj 的数量即可。答案具有单调性,考虑二分。
手写二分太过麻烦。在 C++ 的 STL 中,有一个很好用的函数:upper_bound。它可以找出在一个有序的数组中大于给定值的第一个元素。举个例子,在数组 a={1,1,4,5,14}a=\{1,1,4,5,14\} 中想要查找第一个大于 44 的数,代码可以写为 int id=upper_bound(a,a+5,4)-a;。其中 id 的值就是 55 的下标,也就是 33
以上算法的时间复杂度为 O(nlogn)O(n \log n),瓶颈在排序和二分部分。
本题还有一个坑:如果数据到达极限,共 10610^6 头奶牛,相邻两头奶牛的 pp 值也是相邻的,这样答案大约是 101010^{10}int 会爆。
学会了这些,代码就能轻松写出了。

代码

CPP
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
int n,d;
int a[1000005];
ll ans=0;
int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>d;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		int x=upper_bound(a+i+1,a+n+1,a[i]+d)-a;
		ans+=x-i-1;
	}
	cout<<ans<<endl;
	return 0;
}
/*
---INFORMATIONS---
TIME:2025-05-14 13:02:02
PROBLEM:P1296
CODE BY __CrossBow_EXE__ Luogu uid967841
*/

评论

5 条评论,欢迎与作者交流。

正在加载评论...