Matrix
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. 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 Source
POJ Founder Monthly Contest – 2008.08.31, windy7926778
|
思路:
1.二分答案,根据矩阵中小于这个数的个数与m的值比较来二分。
2.怎样在矩阵中查找呢?方法也是枚举+二分。仔细观察会发现矩阵每列的值满足单调性(每行不满足),所以想到枚举每列,在每列中找到该列小于这个数的值求和就够了。
ps:二分时注意向上取整还是向下取整,然后注意用long long 就够了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
//#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 50005
#define mod 1000000000
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
ll n,m,ans;
ll f(ll x,ll y)
{
return x*x+100000*x+y*y-100000*y+x*y;
}
ll calnum(ll k)
{
ll i,j;
ll le,ri,mid,sum=0;
for(j=1;j<=n;j++) // 对每列进行枚举
{
le=1;
ri=n+1;
while(le<ri) // 找比k小的数
{
mid=(le+ri)>>1;
if(f(mid,j)>=k) ri=mid;
else le=mid+1;
}
sum+=le-1;
}
return sum;
}
void solve()
{
ll le,mid,ri,t;
ri=1LL<<50;
le=-ri;
while(le<ri) // 二分找答案
{
mid=(le+ri)>>1;
t=calnum(mid);
if(t>=m) ri=mid;
else le=mid+1;
}
ans=le-1;
}
int main()
{
int i,j,t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld",&n,&m);
solve();
printf("%lld\n",ans);
}
return 0;
}