POJ 3685

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/83626882

题意 给你 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;
}

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/83626882
POJ
今日推荐