CDOJ 1087 基爷的中位数 二分

本文介绍了一种求解给定整数集合中任意两数之差绝对值中位数的有效算法。通过先对整数进行排序,再利用二分查找技术确定中位数的具体位置。文章详细解释了算法步骤,并提供了具体的实现代码。

给你NN个数,X1,X2,...,XNX1,X2,...,XN, 基爷让我们计算任意两个数差的绝对值 XiXj∣Xi−Xj∣ (1i<jN)(1≤i<j≤N) 。 这样,我们可以得到 C2NCN2 个数。

现在,基爷希望聪明的你能用一个简单的程序求出这 C2NCN2 个数的中位数!


输入有多组数据。

每组数据,第一行一个整数 NN,第二行给出 NN 个整数 X1,X2,...,XNX1,X2,...,XN|Xi|1,000,000,000|Xi|≤1,000,000,000; 3N100,0003≤N≤100,000

当这 C2NCN2 个数的个数为偶数 MM 的时候,取第 M2⌊M2⌋ 个最小的数作为中位数 ( 别问为什么,这就是基爷的中位数! )

刚开始想了好久也没明白怎么二分,然后后来还是看了看别人的代码- -(但是这次没有细看),又仔细地想,就想出来了

先把x序列sort一下

我们可以先找到中位数的位置,从1开始计数,第n*(n-1)/2就是所求的中位数,假设这个中位数是x。
当然,我们就是要求这个x是多少,所以可以二分枚举。
对于区间[l,r],算mid在第几位上,加入mid所在的位数太靠后,就是[l,mid],太靠前,就是[mid+1,r]。
我的思路就是,对于这个mid,算所有的<=mid的数共有多少个,假设有y个,我只需要y>=mid的这个最小的mid,就是要求的中位数。
然后怎么算它在第几位呢,我的算法就是所有差值<mid+1的,枚举每个ai为xi,然后后面所有的为xj,这个差值肯定是递增的,然后lower_bound找到mid+1所在的位置就行,然后枚举完,也就算完了

这个是nloglog的做法,貌似还有nlog的,今天就先不研究了。

具体看代码吧:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100004
long long num[maxn];
int main()
{
	//freopen("input.txt", "r", stdin);
	long long n;
	while (scanf("%lld", &n) != EOF)
	{
		for (int i = 0; i < n; ++i)
			scanf("%lld", &num[i]);
		sort(num, num + n);
		long long pos = n*(n - 1) / 2;
		pos = (pos + 1) >> 1;
		long long l = 0, r = 2000000005, mid, ans = -1;
		while (l < r)
		{
			mid = (l + r) >> 1;
			long long tmp = 0;
			for (int i = 0; i < n; ++i)
			{
				tmp += lower_bound(num + i + 1, num + n, num[i] + mid + 1) - num - i - 1;
				//printf("%lld\n", tmp);
			}
			if (tmp >= pos)
				r = mid;
			else
				l = mid + 1;
		}
		printf("%lld\n", r);
	}
	//system("pause");
	//while (1);
	return 0;
}


### CDOJ 300 木杆上的蚂蚁 #### 题目描述 题目涉及若干只蚂蚁在一个长度为 \( L \) 的水平木杆上移动。每只蚂蚁初始位置和方向已知,当两只蚂蚁相遇时会立即掉头反向行走。目标是计算所有蚂蚁最终离开木杆的时间以及它们的顺序。 --- #### 解决方案概述 该问题的核心在于模拟蚂蚁的行为并处理碰撞事件。尽管表面上看起来需要复杂的碰撞检测逻辑,但实际上可以通过一种巧妙的方式简化问题:假设蚂蚁在碰撞时不改变方向,则可以忽略碰撞的影响[^2]。因此,只需关注每只蚂蚁到达木杆两端所需时间即可。 以下是解决问题的主要思路: 1. **输入解析** 输入数据包括测试用例数量 \( T \),每个测试用例包含木杆长度 \( L \) 和蚂蚁的数量 \( N \)。对于每只蚂蚁,记录其初始位置和移动方向(左或右)。 2. **时间和顺序计算** 对于每只蚂蚁: - 如果它朝左移动,则离木杆左侧的距离为其当前位置; - 如果它朝右移动,则离木杆右侧的距离为 \( L - \text{当前蚂蚁的位置} \)。 将这些距离存储下来,并按升序排列以确定蚂蚁离开木杆的顺序。 3. **输出结果** 输出每只蚂蚁离开木杆的时间及其编号。 --- #### Python 实现代码 以下是一个完整的 Python 实现: ```python t = int(input()) # 测试用例数量 for case in range(1, t + 1): n, l = map(int, input().split()) # 蚂蚁数量和木杆长度 ants = [] for _ in range(n): idx, pos, direction = input().split() idx = int(idx) pos = int(pos) if direction == 'L': time_to_fall = pos # 到达左边所需时间 else: time_to_fall = l - pos # 到达右边所需时间 ants.append((time_to_fall, idx)) # 按照掉落时间排序 sorted_ants_by_time = sorted(ants, key=lambda x: x[0]) # 提取原始索引以便后续匹配 original_indices = list(range(len(sorted_ants_by_time))) # 打印结果 print(f"Case #{case}:") for ant_index in original_indices: print(sorted_ants_by_time[ant_index][1], end=" ") print() ``` --- #### 关键点解释 1. **碰撞不影响总时间** 假设蚂蚁在碰撞时不改变方向,则整个过程中的最大时间为任意一只蚂蚁到最近端点的最大距离。这使得我们可以跳过复杂的状态更新操作[^2]。 2. **效率优化** 使用内置函数 `sorted` 可以高效完成排序任务,算法整体复杂度为 \( O(N \log N) \)。 3. **边界条件** 特殊情况包括仅有一只蚂蚁的情况或者所有蚂蚁都朝同一方向移动的情形。程序应能正确处理此类场景。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值