标签:++i 指针 turn nlogn scanf check 复杂 inline ret
题意:给出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\))
#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\n",l);
}
return 0;
}
标签:++i 指针 turn nlogn scanf check 复杂 inline ret
原文地址:https://www.cnblogs.com/yu-xing/p/10360672.html