POJ 3685

题意 给你 n 阶一个矩阵  Aij = i*i + i*100000 - j*100000 +i*j

求第 m 大的数字 

先输入 T 之后 T 组数据, 每次输入 n ,m。

首先看一下范围 发现超不了 LL,之后找一下规律,发现 i 和 Aij 是正相关的,i 大则 Aij 也会大,但是似乎并没有找到什么规律,这道题更多的是找到 一个数字对吧 找到第 K 大的数,代表有个 K-1个数字 比 它大,而 i 根 Aij 是正相关, 所以可以尝遍历 ai j    j (1 -> n) 但是这样做可以优化, 暴力搜索总是不如二分搜索来的快 ,但是我们如果二分,排序的问题又有点费力,我们只知道二分一下 这个数是什么,并不知道它排第几位对吧,不得不说 之后一步我看了一下大犇们的博客,发现确实脑洞大开,我们不如从整个数字范围开始二分,找一个数,看一下他能不能在 Aij 之中排到我们想要的位置,这一步确实看得我很惊讶。。。。

总结一下:

       在数据范围内选一个数,看一下他在 A矩阵中 有几个比它更大的数,通过二分搜索,每次出现一个比它大的 就计数,知道简单遍历完毕整个 Aij (如果 遍历 i 而二分 j 那么效率是 O(n*logn)可以接受) 之后至于我们如何找到这个数 就是通过整个实属范围内大型二分搜索(真的让人受益匪浅。。没想到二分可以这么用)

 

 

 

以下为 AC代码

 

 

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long int LL;
LL n,m;
LL cal(LL i,LL j)
{
    return i*i+j*j+i*j+100000*i-100000*j;
}
LL findd(LL x)
{
    LL num=0;
    LL l,r,mid,i;
    for(i=1;i<=n;i++)
    {
        l=1,r=n+1;
        mid=(l+r)>>1;
        while(l<r)
        {     
            if(cal(mid,i)>=x)
                r=mid;
            else 
                l=mid+1;
            mid=(l+r)>>1;
        }
        num += mid-1;
    }
    return num;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&m);
        LL l,r,mid;
        l=-1e12,r=1e12;
        mid = (l+r)>>1;
        while(l<r)
        {
            if(findd(mid)>=m)r=mid;
            else l=mid+1;
            mid = (l+r)>>1;
        }
        printf("%lld\n",mid-1);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值