zoukankan      html  css  js  c++  java
  • poj 3685 Matrix 【二分】

    <题目链接>

    题目大意:

    给你一个n*n的矩阵,这个矩阵中的每个点的数值由   i2 + 100000 × i + j2 - 100000 × j + i ×  这个公式计算得到,N(1 ≤ N ≤ 50,000),现在问你,这个矩阵中第m小的数是多少?

    解题分析:
    仔细研究这个式子不难发现,在每一列,即 j 一定的时候,这个式子的数值随着 i 的增大而增大,也就是说,在这个矩阵的每一列,式子满足从上自下递增的规律,符合单调性。我们由此可以想到二分,先二分答案,即二分出第m 小的数数值为多少,然后再根据二分出的答案mid,遍历一遍矩阵的每一列,对每一列进行二分,快速求得每一列数值小于mid 的数的个数,然后将它们相加,以此来判断二分出的答案的正确性。

     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 typedef long long ll;
     5 ll n,m;
     6 ll calculate(ll i,ll j){
     7     return i*i+100000*i+j*j-100000*j+i*j;
     8 }
     9 bool check(ll x){
    10     ll sum_smaller=0;
    11     for(int j=1;j<=n;j++){
    12         ll l=0,r=n;
    13         ll ans=0;
    14         while(l<=r){
    15             ll mid=(l+r)>>1;
    16             if(calculate(mid,j)<x)ans=mid,l=mid+1;  //因为后面要根据小于x的数的个数,来判断x是否为第m小的数,所以这里只取<x的数,用"<" 
    17             else r=mid-1; 
    18         }
    19         sum_smaller+=ans;
    20     }
    21     return sum_smaller<m;
    22 }
    23 int main(){
    24     int T;scanf("%d",&T);
    25     while(T--){
    26         scanf("%lld%lld",&n,&m);
    27         ll l=-100000*n,r=3*n*n+100000*n;
    28         ll ans;
    29         while(l<=r){
    30             ll mid=(l+r)>>1;
    31             if(check(mid))ans=mid,l=mid+1;  //当比mid小的数<m个时,继续二分,直到恰好比mid小的数的个数>=m时,此时枚举的mid一定是矩阵中的数
    32             else r=mid-1;
    33         }
    34         printf("%lld
    ",ans);
    35     }
    36     return 0;
    37 }

    2018-09-21

  • 相关阅读:
    https原理以及golang基本实现
    关于Goroutine与Channel
    Golang中log与fmt区别
    liteide使用中的注意点
    Golang中的error类型
    关于linux中的目录配置标准以及文件基本信息
    Godep的基本使用
    Golang基本类型整理
    ssh使用技巧
    看完让你彻底搞懂Websocket原理
  • 原文地址:https://www.cnblogs.com/00isok/p/9686300.html
Copyright © 2011-2022 走看看