二分 - Matrix - POJ - 3685

二分 - Matrix - POJ - 3685

題意:

ni,jAij=i2+100000×i+j2100000×j+i×j,M.有一個n階方陣 第i行,j列的值A_{ij} =i^2 + 100000 × i + j^2 - 100000 × j + i × j,\\需要找出這個方陣的第M小值.

TnmT組測試用例,\\每組包括兩個整數n和m。

數據範圍:

1n500001mn×nTime limit6000msMemory limit65536kB1 ≤ n ≤ 50000,1 ≤ m ≤ n × n\\Time \ limit:6000 ms,Memory \ limit:65536 kB

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

分析:

m二分答案第m小的數。

checkmidm關鍵在於check函數如何判定mid是否爲第m小的數。

j我們發現,當列號j確定時,f(i,j)=i2+100000×i+j2100000×j+i×j=f(i)=i2+(100000+j)×i+C,Cf(i,j)=i^2 + 100000 × i + j^2 - 100000 × j + i × j=f(i)=i^2 + (100000+j) ×i+C,其中C是常數。

1i,jnf(i)調調因爲1 ≤ i,j≤n,故容易得f(i)是單調遞增的。也就是每一列的值都是單調遞增的。

jjmid調因此,我們可以枚舉每一列j,計算第j列中有多少數小於等於mid,由於每一列的數是單調的,又可以用二分。

nmid最後累加起來就得到n列中小於等於mid的數的個數。

mid>=mr=midl=mid+1若小於等於mid的數的個數>=m個,則r=mid,否則l=mid+1。

代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

#define ll long long
#define P pair<int,int>
#define x first
#define y second

using namespace std;

ll T,n,m;

ll f(ll i,ll j)
{
    return i*i+100000*i+j*j-100000*j+i*j;
}

ll cal(ll t)
{
    ll l,r,res=0;
    for(ll j=1;j<=n;j++)  
    {
        l=0,r=n;
        while(l<r)
        {
            ll mid=l+r+1>>1;
            if(f(mid,j)<=t) l=mid;
            else r=mid-1;
        }
        res+=l;
    }
    return res;
}

int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n>>m;

        ll l=-1e12,r=1e12;
        while(l<r)
        {
            ll mid=l+r>>1;
            if(cal(mid)>=m) r=mid; 
            else l=mid+1;
        }
        
        printf("%lld\n",l);
    }
    
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章