题意:给出n只袜子和一个k,每只袜子的长度不同。求两只袜子相差值从小到大第k位的袜子是哪两只。
思路:虽然题目给了20s,粗算之下暴力不会超时,然而数组是很多组的,所以纯暴力会超时。于是就想到了二分袜子的差值,本题对于数据的处理很苛刻,是一道卡时的好题。
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<vector>
#include<cmath>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
ll num[100005];
int n;
ll k;
ll cal(int mid){ //计算两数相差小于等于mid的情况数总和
int i = 0,j = 1;
ll cnt = 0;
ll tot = 0;
while(i < n){
if(j<n && num[j]-num[i]<=mid){
j ++;
cnt ++;
}
else{
tot += cnt;
cnt = cnt-1; //num[j]到num[i]之差小于等于mid的有cnt个,那么num[i+1]到num[j]的有cnt-1个
i ++;
}
}
return tot;
}
int main(){
while(~scanf("%d%lld", &n, &k)){
if(!n && !k) break;
for(int i = 0;i < n;i++) scanf("%lld", num+i);
sort(num,num+n);
ll l = 1,r = 1000000009; //二分两数之差,找到小于等于此差的情况数恰好大于k的时候
while(l < r){
ll mid = (l+r)>>1;
ll tot = cal(mid);
if(tot < k) l = mid+1;
else r = mid;
}
ll rest = k-cal(r-1); //两数相减为r的情况中,所求答案位于第几位
int i = 0,j = 1;
ll cnt = 0;
while(i < n){
if(!rest) break;
if(j<n && num[j]-num[i]<=r){
if(num[j]-num[i] == r){
rest --;
if(!rest) printf("%lld %lld\n", num[i], num[j]);
}
j ++;
}
else {
i++;
}
}
/*int flag = 0;
for(int i = 0;i < n;i++){
if(flag) break;
for(int j = i+1;j < n;j++){
if(num[j]-num[i] == r){
rest --;
if(!rest){
flag = 1;
printf("%d %d\n", num[i], num[j]);
break;
}
}
}
}
*/
}
return 0;
}