POJ - 3579 二分枚举答案 查找第K大

35 篇文章 1 订阅
29 篇文章 0 订阅

题目

在这里插入图片描述

题解思路

很显然不能直接求出ans数组,先将数组排序,因为是任意差值的绝对值,顺序并不影响,我们对答案进行枚举。ans数组大小为n*(n-1)/2 ,这是可以根据等差数列求和得到的。
答案需要介于符合大于一半的ans数组数到不符合的左右。
设枚举的答案为p

当我们排序完后,很容易枚举出p小于等于那些差值的数量和sum,利用二分函数就可以得到,不论奇数偶数都应该大于ans数组的一半,因为sum包含了p自己的值。

这里还有个有点玄学的问题。
关于二分出来的边界问题,如果验证出来要从下界更新且都为正整数,我们需要用t2-t2>1来退出二分
例如
1 2,mid为1符合答案,下界又更新为1,这样就无限循环了。
此时还不能对上界进行更改,保证上界不符合答案。(问就是验证边界改变了,玄学二分)

AC代码
#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

long long  n,k;
long long a[100100];

bool che(long long p)
{
    long long sum = 0 ;
    for (int i = 1 ; i <= n ; i++ )
        sum += n - (lower_bound(a+1,a+n+1,p + a[i])-a-1);
    return sum > k ; //加上了自己
}
int main ()
{
    while(~scanf("%lld",&n))
    {
        long long t1 = 0 , t2 ;
        k = n*(n-1)/4;
        for (int i = 1 ; i <= n ; i++ )
            scanf("%lld",&a[i]);
        sort(a+1,a+1+n);
        t2 = a[n] - a[1] ;
        while( t1 < t2 - 1)
        {
            long long mid = (t2-t1)/2+t1 ;
            if ( che(mid) )
            {
                t1 = mid;
            }else
                t2 = mid ;
        }
        printf("%lld\n",t1);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值