POJ 3685 二分套二分求解
阿新 • • 發佈:2018-12-17
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
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階矩陣Aij
分析:首先你要知道這個式子是關於i遞增的二元函式,如果是知道這一步,那剩下的就交給二分
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <cstdlib> #include <cstring> using namespace std; typedef long long ll; #define rep(i,l,r) for(int i=l;i<=r;i++) const int N = 3e5 + 10; const ll INF = 0x3f3f3f3f3f3f3f; ll m; ll n; ll Get(ll x,ll y){ return x*x+100000*x+y*y-100000*y+y*x; } bool solve(ll x)//列舉小於當前x的個數有幾個 { int tot=0; rep(j,1,n){//每一列去列舉 int l=0,r=n+1; while(r-l>1) { int mid=(l+r)>>1; if(Get(mid,j)<x) l=mid;//找到最後在當前列下,有幾行的元素是小於當前x的 else r=mid; } tot+=l;//把滿足的每列的行的個數相加 } return tot<m;//如果小於當前x的數是小於m個,那就是說明x太小了,那就是需要增加下界 } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif // ONLINE_JUDGE int t; scanf("%d",&t); while(t--){ scanf("%lld%lld",&n,&m); ll lb = -INF, ub = INF;//列舉可能的值,因為數值很大,因此希望是從無窮小到無窮大之間選擇 while(ub-lb>1){ ll mid=(lb+ub)>>1; if(solve(mid)) lb=mid; else ub=mid; } printf("%lld\n",lb); } return 0; }