• POJ 3685:Matrix 二分


    Matrix
    Time Limit: 6000MS   Memory Limit: 65536K
    Total Submissions: 5489   Accepted: 1511

    Description

    Given a N × N matrix A, whose element in the i-th row and j-th column Aij is an number that equals i2 + 100000 × i + j2 - 100000 × j + i × j, you are to find the M-th smallest element in the matrix.

    Input

    The first line of input is the number of test case.
    For each test case there is only one line contains two integers, N(1 ≤ N ≤ 50,000) and M(1 ≤ M ≤ N × N). There is a blank line before each test case.

    Output

    For each test case output the answer on a single line.

    Sample Input

    12
    
    1 1
    
    2 1
    
    2 2
    
    2 3
    
    2 4
    
    3 1
    
    3 2
    
    3 8
    
    3 9
    
    5 1
    
    5 25
    
    5 10
    

    Sample Output

    3
    -99993
    3
    12
    100007
    -199987
    -99993
    100019
    200013
    -399969
    400031
    -99939

    给了一个N*N的矩阵,每个位置上的数由该位置的下标i,j决定。然后问这个矩阵中第m小的数。

    通过这道题好好总结了一下二分,总算是深刻理解了一下。

    第一个二分枚举答案,第二个二分,通过公式可知,函数跟j不是单调的关系,但跟i是单调的关系,所以每次枚举j,然后二分i的值。

    代码:

    #include <iostream>  
    #include <algorithm>  
    #include <cmath>  
    #include <vector>  
    #include <string>  
    #include <cstring>  
    #pragma warning(disable:4996)  
    using namespace std;
    
    #define maxn 1e12
    typedef long long ll;
    
    ll m, n;
    ll le, ri, mid;
    
    ll cal(ll i, ll j)
    {
    	return i*i + 100000 * i + j*j - 100000 * j + i*j;
    }
    
    ll check(ll x)
    {
    	ll i, le, ri, mid, cnt;
    	
    	ll temp;
    	cnt = 0;
    	for (i = 1; i <= n; i++)
    	{
    		le = 1;//mid不能取到0,所以这里的le取1
    		ri = n + 1;//因为mid可能要取到n,所以这里的ri要取到比n大的数
    		
    		mid = le + (ri - le) / 2;
    		while (le < ri)
    		{
    			temp = cal(mid, i);
    			if (cal(mid, i) < x)
    			{
    				le = mid + 1;
    			}
    			else
    			{
    				ri = mid ;
    			}
    			mid = le + (ri - le) / 2;
    		}
    		cnt += (mid - 1);//经过计算,这里始终是多计算了一个1,所以要在这里把它扣掉
    	}
    	return cnt;
    }
    
    int main()
    {
    	//freopen("i.txt", "r", stdin);
    	//freopen("o.txt", "w", stdout);
    
    	int test;
    	scanf("%d", &test);
    
    	while (test--)
    	{
    		scanf("%lld%lld", &n, &m);
    		le = -maxn;
    		ri = maxn;
    
    		mid = le + (ri - le) / 2;
    		while (le < ri)
    		{
    			if (check(mid) < m)//检查小于 mid 的个数
    			{
    				le = mid + 1;
    			}
    			else
    			{
    				ri = mid;
    			}
    			mid = le + (ri - le) / 2;
    		}
    		printf("%lld
    ", mid-1);//有m个小于mid的数,所以第m大的数就是mid-1
    	}
    
    	//system("pause");
    	return 0;
    }


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    Delphi 控件使用谷歌浏览器控件chromium 安装包是 dcef3-20140522 --碰到的问题
    salesforce零基础学习(九十九)Git 在salesforce项目中的应用(vs code篇)
    Salesforce LWC学习(二十) CLI篇:新版本不支持Audience解决方案
    Salesforce LWC学习(十九) 针对 lightning-input-field的label值重写
    apt安装后需要移除的问题
    mysql 触发器阻止不合理数据插入
    本机环境virtualbox出现问题重装
    php 版本升级后需要对代码进行兼容性检测
    k8s使用需认证的私服仓库
    无法启动electron,提示node_modules/electron/dist/chrome-sandbox is owned by root and has mode 4755.
  • 原文地址:https://www.cnblogs.com/lightspeedsmallson/p/4928107.html
Copyright © 2020-2023  润新知