poj3579(二分求解第k小/大值)

来源:互联网 发布:章鱼彩票安全吗 知乎 编辑:程序博客网 时间:2024/06/05 11:32
/*translation:给出串数列,其中每每两个数的差的绝对值构成一个集合,求这个集合中的中位数。solution:二分法求第k小/大首先枚举第k小/大的数值,然后判断是否有k个值小/大于等于它即可,然后不断逼近。具体快速判断的方法见代码注释。具体复杂度接近O(n)note:*:注意本题快速判断小于等于mid值的个数的方法date:2016.11.4*/#include <iostream>#include <cstdio>#include <algorithm>using namespace std;const int maxn = 100000 + 5;typedef long long ll;ll x[maxn], n;ll median_cnt;bool check(ll mid)//检查小于等于mid的数有多少个{int cnt = 0, j = 1;for(int i = 2; i <= n; i++){while(x[i] - x[j] > mid)j++;//当x[i]和x[j]的差太大时,将j移动到差刚刚好小于mid的位置,由于cnt += (i - j);//数组是排好序的,所以此时在j后面的位置和x[i]的差绝对小于mid}//故而此时直接加上j和i的位置差距即可。if(cnt >= median_cnt)return true;return false;}int main(){//freopen("in.txt", "r", stdin);    while(~scanf("%lld", &n)){for(int i = 1; i <= n; i++)scanf("%lld", &x[i]);sort(x + 1, x + n + 1);median_cnt = n * (n - 1) / 2;if(median_cnt & 1)median_cnt = median_cnt / 2 + 1;elsemedian_cnt /= 2;if(n == 1){printf("0\n");continue;}ll lb = 0, ub = x[n];for(int i = 0; i < 50; i++){ll mid = (lb + ub) / 2;if(check(mid))ub = mid;//如果检查mid比中位数大elselb = mid;}printf("%lld\n", ub);    }    return 0;}

0 0
原创粉丝点击