题目大意

给定N个数,这些数字两两求差构成C(N,2)(即N*(N-1)/2)个数值,求这C(N,2)个数的中位数。N <= 100000.

题目分析

根据数据规模N最大为100000,可知不能直接求每两个数的查找(O(N*N)复杂度),然后排序,再求中位数。考虑使用二分法查找满足要求的中位数: 
    先将原数组排序,然后假设数k为中位数,那么如果这N个数字构成的C(N,2)个差值中小于k的小于C(N,2)/2个,则k需要增加;如果小于等于k的数字大于等于C(N,2),那么k需要减少。最后求出的k是恰好满足C(N,2)个差值中小于等于k的数大于等于C(N,2)个,且差值中存在k 的最小值。

实现(c++)

#include<stdio.h>
#include<algorithm>
using namespace std;
#define MAX_N 100005 int an[MAX_N];
int DiffKLessThanHalf(int n, int k){
int sum = 0;
int max_pair = n*(n-1) / 2;
max_pair = max_pair / 2 + max_pair % 2; //小于等于中位数的最少个数
bool flag = false;
for (int i = 0; i < n - 1; i++){
int beg = i + 1, end = n;
while (beg < end){
int mid = (beg + end) / 2;
if (an[mid] - an[i] == k){ //差值中存在k,说明k可以做为中位数
flag = true;
}
if (an[mid] - an[i] <= k)
beg = mid + 1;
else
end = mid;
}
sum += (beg - i - 1); //和 an[i] 的差值小于等于k的个数 为 beg - i - 1
if (sum >= max_pair && flag)//小于等于k的个数 至少为C(N,2) 且 存在差值等于k,说明k可以作为一个中位数,
//但后续需要继续求满足这种条件的最小的k。直接返回
return 2;
}
if (sum < max_pair) //小于等于k的个数 小于 C(N,2),说明中位数 > k
return 0;
return 1;
} int main(){
int n; while (scanf("%d", &n) != EOF){
for (int i = 0; i < n; i++){
scanf("%d", &an[i]);
}
sort(an, an + n);
int beg = 0, end = an[n-1] - an[0] + 1;
int rr = 0;
while (beg < end){
int mid = (beg + end) / 2;
int result = DiffKLessThanHalf(n, mid);
if (result == 0)
beg = mid + 1;
else if (result == 1){
end = mid;
}
else{
end = mid;
rr = mid; //记录下一个可能的中位数值
}
}
printf("%d\n", rr);
}
return 0;
}

poj_3579 二分法的更多相关文章

  1. C语言两种查找方式(分块查找,二分法)

    二分法(必须要保证数据是有序排列的):   分块查找(数据有如下特点:块间有序,块内无序):    

  2. poj3122-Pie(二分法+贪心思想)

    一,题意: 有f+1个人(包括自己),n块披萨pie,给你每块pie的半径,要你公平的把尽可能多的pie分给每一个人 而且每个人得到的pie来自一个pie,不能拼凑,多余的边角丢掉.二,思路: 1,输 ...

  3. 二分法&三分法

    ural History Exam    二分 #include <iostream> #include <cstdlib> using namespace std; //二分 ...

  4. [No000087]Linq排序,SortedList排序,二分法排序性能比较

    using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; ...

  5. [PHP]基本排序(冒泡排序、快速排序、选择排序、插入排序、二分法排序)

    冒泡排序: function bubbleSort($array){ $len=count($array); //该层循环控制 需要冒泡的轮数 for($i=1;$i<$len;$i++){ / ...

  6. iOS常见算法(二分法 冒泡 选择 快排)

    二分法: 平均时间复杂度:O(log2n) int halfFuntion(int a[], int length, int number)  { int start = 0; int end = l ...

  7. java简单的二分法排序

    二分法排序的思路:数据元素要按顺序排列,对于给定值 x,从序列的中间位置开始比较,如果当前位置值等于 x,则查找成功:若 x 小于当前位置值,则在数列的前半段中查找:若 x 大于当前位置值则在数列的后 ...

  8. 使用二分法查找mobile文件中区号归属地

    #!/usr/bin/env python #coding:utf-8 ''' Created on 2015年12月8日 @author: DL @Description: 使用二分法查找mobil ...

  9. Atitit 迭代法  “二分法”和“牛顿迭代法 attilax总结

    Atitit 迭代法  "二分法"和"牛顿迭代法 attilax总结 1.1. ."二分法"和"牛顿迭代法"属于近似迭代法1 1. ...

随机推荐

  1. 简易web项目jdbcUtil

    jdbc.username=root jdbc.password=root jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://mini1: ...

  2. 【WPF】C#代码动态添加控件的Margin属性

    需求:一组按钮的数据是从服务器中Json数据发过来的,需要根据这个Json数据动态地添加这组按钮. 工具:使用http://www.newtonsoft.com/json来解析Json. 过程:C#代 ...

  3. MapReduce的集群行为和框架

    MapReduce的集群行为 MapReduce的集群行为包括: 1.任务调度与执行MapReduce任务由一个JobTracker和多个TaskTracker两类节点控制完成.(1)JobTrack ...

  4. am335x Linux kernel DTS pinmux 定义记录

    记录am335x TI PDK3.0 Linux Kernel 设备的pinmux 的配置 在TI 的Linux kernel 设备树里面,有很多关于pinctrl-single,pins 的配置, ...

  5. JavaScrip——DOM操作(属性操作)

    Attribute a.setAttribute("属性名","属性值")——设置属性 a.getSttribute("属性名")——获取属 ...

  6. 经典SQL回顾之晋级篇

    上篇博文在说SQL基础的时候,有一个地方有点误导大家,文中说到SQL 中的substring()和C#中的substring()相同,这有点歧义.基本原理虽然相同,但是有一点很不一样,就是C#中索引是 ...

  7. Golang 类型转换整理

    1.整形到字符串: var i int = 1 var s string s = strconv.Itoa(i) 或者 s = FormatInt(int64(i), 10) 2.字符串到整形 var ...

  8. LINQ操作符三:限制操作符

    where是限制操作符,它将过滤标准应用在序列上,按照提供的逻辑对序列中的数据进行过滤. where操作符不启动查询的执行.当开始对序列进行遍历时才开始执行,此时过滤条件将被应用到查询中. 示例: / ...

  9. Using org.hibernate.id.UUIDHexGenerator which does not generate IETF RFC 4122 compliant UUID values;

    项目部署,启动过程中有以下警告: [WARN]: Using org.hibernate.id.UUIDHexGenerator which does not generate IETF RFC 41 ...

  10. 自然语言交流系统 phxnet团队 创新实训 个人博客 (一)

    项目涉及链表操作,遂整理: 使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理.但是链表失去了数组随机读取的优点,同时链表由于增加了结点 ...