• ACM刷题之路(十八)二分 2019暑期集训 POJ 3579 Median


    题目链接:传送门

    Description

    Given N numbers, X1, X2, ... , XN, let us calculate the difference of every pair of numbers: ∣Xi - Xj∣ (1 ≤ i j N). We can get C(N,2) differences through this work, and now your task is to find the median of the differences as quickly as you can!

    Note in this problem, the median is defined as the (m/2)-th  smallest number if m,the amount of the differences, is even. For example, you have to find the third smallest one in the case of m = 6.

    Input

    The input consists of several test cases.
    In each test case, N will be given in the first line. Then N numbers are given, representing X1, X2, ... , XN, ( Xi ≤ 1,000,000,000  3 ≤ N ≤ 1,00,000 )

    Output

    For each test case, output the median in a separate line.

    Sample Input

    4
    1 3 2 4
    3
    1 10 2

    Sample Output

    1
    8

    题意:每一组数据给一个n,后面给n个数,求这些数之间的差绝对值的中位数,比如例子1 3 2 4 ,差为1,1,1,2,2,3,如果个数为偶数则取中间前面,奇数取中间的数。

    分析:

    要求差的中位数,最暴力的就是把所有的差都算出来,再sort排序,然后取中间的数输出,当然肯定超时。

    我的做法是用两个二分,第一个二分中位数的值,第二个二分试探这个值的可行性

    比如例子:

    4

    1 3 2 4

    先对它排序  放入vector  然后是1 2 3 4

    那么它一定有6个差  计算方法为1 + 2 + 3个差   即(1+n-1)*n/2 == (n-1)*n/2;

    差的最小值假设是0,就是二分的起点s = 0 ;差一定大于0

    最大值假设是a[n-1]-a[0]+1,也就是二分的终点e = 4;差一定小于最大值和最小值的差

    接着先使用一次二分,找可能的中位数的值,日常  while(s<e){}   走起

    第一次二分找到mid=(s+e)/2 = 2;

    假设有m个差大于要求的3   :    比如1 2 3 4 5 6这样6个数  题目要求的中位数是第三个数

    说明这个mid太小了,答案在mid到e的范围内,所以让s=mid;

    否则,答案肯定在s到mid的范围内,让e=mid;

    题目第一个例子的第一次二分,mid=2;

    那么4-2    4-1   3-1 这三个差要大于等于mid值,即不满足3>3

    所以答案在s=0到mid=2的范围内,以此类推,二分下去

    最后二分终止时就可以找到正确答案。

    但是不明白这题为什么在s=mid;或者e=mid的地方不用加1减1都可以不卡死循环

    下面贴我自己手打的代码 464K 688MS

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    using namespace std;
    vector<int>v;
    int xiangshu, n;
    bool dd(int x) {
    	int sum = 0;
    	for (int i = 0; i < n; i++) {
    		sum += v.end() - lower_bound(v.begin(), v.end(), v[i] + x) ;
    	}
    	if (sum > xiangshu) return true;
    	return false;
    }
    int main()
    {
    	int num;
    	while (~scanf_s("%d", &n)) {
    		v.clear();
    		for (int i = 0; i < n; i++) {
    			scanf_s("%d", &num);
    			v.push_back(num);
    		}
    		xiangshu = n * (n - 1) / 2;
    		if (xiangshu & 1) {
    			xiangshu = xiangshu / 2;
    		}
    		else {
    			xiangshu /= 2;
    		}
    		sort(v.begin(), v.end());
    		int s = 0, e = v[n - 1] - v[0] + 1;
    		while (s < e - 1) {
    			int mid = (s + e) / 2;
    			if (dd(mid)) {
    				s = mid ;
    			}
    			else {
    				e = mid;
    			}
    		}
    		printf("%d
    ", s);
    	}
    	return 0;
    }
  • 相关阅读:
    leecode 91. 解码方法
    leecode 166. 分数到小数
    剑指 Offer 31. 栈的压入、弹出序列
    leecode 386. 字典序排数
    LeetCode 311 稀疏矩阵的乘法
    leecode 89. 格雷编码
    leecode 79. 单词搜索
    leecode 207. 课程表
    QT -- 解决:Error: Could not decode "*.cpp" with "UTF-8"
    VS+QT -- 没有PRO文件的问题
  • 原文地址:https://www.cnblogs.com/yyzwz/p/13393263.html
Copyright © 2020-2023  润新知