POJ 3685 Matrix 二分

POJ 3685 Matrix 二分 

题意:首先分析 i^{2} + 100000 × i +j^{2} - 100000 × j + i × j 这个式子,可以发现当j固定时,整个式子的值是递增的,因此可以得出一个结论:在矩阵的同一列中,从上往下数值是递增的,因此可以利用二分枚举每一列的值。

   二分的核心思想:求数组中的第m小的数y,转换成求数组中<x的数量>=m的最小x,则y=x-1(待会证明), 所以该题二分套二分的核心思想就是:首先第第一层外层二分法枚举x,使得数组中<x的数量>=m(即合法),从而无限逼近直到得出最小的x,然后第二层内层层再用二分法求出在数组中<x的数量的个数,这个地方又是一个典型的二分,将求出在数组中<x的个数转换为求出值>=x的最小的下标p,那么<x的最大的下标q就是该下标减1即q=p-1了,然后统计个数就好。

    但是这两层二分都各有一个需要注意的问题:

    1.第一层二分中为什么y==x-1?因为假设y!=x-1,那么存在一个小于x的数x-1,使得

<x-1的数量>=m与x是最小值矛盾,固得证。其实这也是整数性质的体现,因为可以这样看,求一个序列中的第m小的数值,则比该值+1的数值w(二分枚举出的,不管数组中存不存在),在数组中<w的数值是有m个的,那么w-1便是该第m小的数值。

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

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值