poj 3685

 /*
    给定n,有n*n个数,有aij=i * i + m * i + j * j - m * j + i * j
    n <= 50000
    m <= 100000
    求所有aij中第m大的数

    还是二分答案,先根据生成的式子,求出最大的和最小的数字,然后二分答案,验证
    我们发现,对于同列的数字,按照行数的增加,数字大小是递增的
    根据这个性质,就很容易验证是否存在>=n*n-m+1个数字>=val了

    看了题一下子就有想法了,结果却wa了一天...原因在于自作聪明地进行数学推论然后非要从同行中进行二分...最后才发现不满足递减性质...不过最后ac的时候还是很爽快的
*/
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#define range(i,a,b) for (long long i=a;i<=b;i++)

using namespace std;

typedef long long ll;

const ll m = 1e5;

ll n;
ll M;

inline ll Int(ll i,ll j)
{
    return i * i + m * i + j * j - m * j + i * j;
}

//找到最小的i,满足>=val
ll findK(ll j,ll val)
{
    ll l(1),r(n);
    while(l+1<r)
    {
        int mid = (l+r)>>1;
        if (Int(mid,j) >= val)
            r = mid;
        else
            l = mid;
    }
    //返回>=val的数字的个数
    if (Int(l,j) >= val)
        return n-l+1;
    if (Int(r,j) >= val)
        return n-r+1;
    return 0;
}

bool test(ll val)
{
    ll ans(0);
    //返回每一行的>=val的数量
    range(c,1,n)
    {
        ans += findK(c,val);
    }

    return ans >= (ll)n*n - M+1;
    //必须要有>=n*n-M+1的数量>=ans,ans才有可能是答案
}

int main()
{
    int t;
    cin>>t;

    range(c,1,t)
    {
        cin>>n>>M;
        ll l(-n*m),r(n*n*3 + n*m);
        while(l+1<r)
        {
            ll mid = (l+r)/2;
            if (mid == 5101786214)
            {
                cout<<"";
            }
            if (test(mid))
            {
                l = mid;
            }
            else
            {
                r = mid;
            }
        }
        if (test(r))
        {
            cout<<r<<endl;
        }
        if (test(l))
        {
            cout<<l<<endl;
        }

    }
    return 0;
}
时间: 2024-08-08 13:57:34

poj 3685的相关文章

POJ 3685 Matrix 二分套二分

POJ 3685 Matrix 二分 题意 有一个N阶方阵,方正中第i行第j列的元素值为\(d_{i,j}=i^{2}+1e5*i+j^{2}-1e5*j+i*j\),我们需要找出这个方阵中第M小的元素值. 解题思路 分析这个公式,我们发现:当j固定的时候,这个公式关于i(取值范围:从0到n)是单调增加的,所以这里我们可以二分一个答案,然后一列一列的找小于(等于)它的个数,这样加起来我们就能知道我们枚举的这个答案是第几小了. 需要注意的是,第一个最外层的二分有点不同,因为我们二分的答案可能不存在

poj 3685 Matrix(二分搜索之查找第k大的值)

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 nu

POJ 3685 二分

Matrix Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 7034   Accepted: 2071 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 ar

POJ 3685 二分套二分

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

Divide and conquer:Matrix(POJ 3685)

矩阵 题目大意:矩阵里面的元素按i*i + 100000 * i + j*j - 100000 * j + i*j填充(i是行,j是列),求最小的M个数 这一题要用到两次二分,实在是二分法的经典,主要是每一列都是按照行来递增的,每一行我们都用二分法找到比mid小的那些数就好了 参考http://blog.csdn.net/nw4869/article/details/24124019 1 #include <iostream> 2 #include <algorithm> 3 #i

POJ - 3685 Matrix

二分kth,答案满足的条件为:m ≤ 小于等于x的值数cntx.x和cntx单调不减,随着x增大,条件成立可表示为:0001111. 本地打一个小型的表可以发现列编号j固定时候,目标函数f(i,j)似乎具有单调性. 变形,f(i,j) = (i+100000+j)*i + j2 - 100000,可以看出确实具有单调性. 于是得到如下算法: 二分x,统计cnt时候,枚举j,再套一个二分. /*****************************************************

POJ - 3685 Matrix 二分

题目大意:有一个N * N的矩阵,其中Aij = i * i + i * 100000 - 100000 * j + j * j + i * j,问这个矩阵中,第M小的数是多少 解题思路:观察这个式子,可以发现j不变的情况下,随着i的增大,Aij也相应增大,由这个受到启发 二分枚举第M小的数,然后按列寻找,找到第一个大于这个数的位置,就可以知道该列中有多少个数是大于这个数的了 #include<cstdio> #include<cstring> #include<algori

POJ 3685 二分套二分(水题

题意:给出一个N*N的矩阵A,A[i][j]的值等于i2 + 100000 ×i + j2 - 100000 × j + i × j,求这个矩阵中第M小的数 代码: 1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 long long N; 5 long long cal(long long i,long long j){ 6 return i*i+100000*i+j*j-100000*j+i*j

POJ 3579 3685(二分-查找第k大的值)

POJ 3579 题意 双重二分搜索:对列数X计算∣Xi – Xj∣组成新数列的中位数 思路 对X排序后,与X_i的差大于mid(也就是某个数大于X_i + mid)的那些数的个数如果小于N / 2的话,说明mid太大了.以此为条件进行第一重二分搜索,第二重二分搜索是对X的搜索,直接用lower_bound实现. #include <iostream> #include <algorithm> #include <cstdio> #include <cmath&g