POJ3579 Median
Posted yu-xing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ3579 Median相关的知识,希望对你有一定的参考价值。
题意:给出N个数,对于存有每两个数的差值的序列求中位数(一共(C_n^2)个),如果这个序列有偶数个元素,就取中间偏小的作为中位数。
思路:
注意到题目中对于每两个数求差值,所有数的排列顺序不影响结果,所以可以先对数组排序。
因为答案具有单调性,所以可以二分答案ans,check函数中求出差值小于等于ans的数对数量cnt,与总方案数(差值序列元素个数)的二分之一比较(中位数),更改ans的上下界。
这里可以枚举每个(a_i) ,统计小于等于(a_i+ans) 的数有多少个,计入cnt变量中。
具体方法:枚举 a[i],?然后二分 i之后的区间,假设a[j]是最后一个小于等于a[i]+ans的值,那么cnt加上j-i的值。
时间复杂度:O((nlog^2n))
优化:依题意,数组中均为非负整数,可利用单调性,用i和j双指针进行优化。
时间复杂度:O((nlogn))
- 其他
- (C_n^2=n*(n-1)/2);
- check函数中注意原序列中元素个数为奇数还是偶数,若是偶数,依题意答案向下取,判断时不加等号。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100005,INF=0x3f3f3f3f;
int n,a[maxn];
bool check(int x){
int cnt=0;
for(int i=1,j=1;i<=n;++i){
while(a[j]<=a[i]+x&&j<=n) ++j;
--j;
cnt+=j-i;
}
if(!(((n*(n-1))>>1)&1)) return cnt < (n*(n-1))>>2;
else return cnt <= (n*(n-1))>>2;
}
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+1+n);
int l=0,r=INF;
while(l<r){
int mid=l+r>>1;
if(check(mid)) l=mid+1;
else r=mid;
}
printf("%d
",l);
}
return 0;
}
以上是关于POJ3579 Median的主要内容,如果未能解决你的问题,请参考以下文章