H

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列的值为 i2 + 100000 × i + j2 - 100000 × j + i × j,求这些矩阵中的第m小的值。
解题思路
暴力的话超时就不讲了,换到二分:首先分析 i2 + 100000 × i + j2 - 100000 × j + i × j 这个式子,可以发现当j固定时,整个式子的值是递增的,因此可以得出一个结论:在矩阵的同一列中,从上往下数值是递增的,因此可以利用二分枚举每一列的值。
该题二分套二分的核心思想就是:首先第第一层外层二分法枚举x,使得数组中<x的数量>=m(即合法),从而无限逼近直到得出最小的x,然后第二层内层层再用二分法求出在数组中<x的数量的个数,这个地方又是一个典型的二分,将求出在数组中<x的个数转换为求出值>=x的最小的下标p,那么<x的最大的下标q就是该下标减1即q=p-1了,然后统计个数就好。
源代码
#include<cstdio>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
#define MM(a) memset(a,0,sizeof(a))
typedef long long LL;
typedef unsigned long long ULL;
const int mod = 1000000007;
const double eps = 1e-10;
const int inf=0x3f3f3f3f;
long long mid,l,r,n,m;
long long v(long long  i,long long j)
{
    return i*i+100000*i+j*j-100000*j+i*j;
}
long long  ok(long long  x)
{
    long long sum=0;
    for(long long  j=1;j<=n;j++)
      {
          long long  l=0,r=n+1;
          while(r-l>1)
          {
               long long  mid=(l+r)>>1;
               if(v(mid,j)>=x)
                     r=mid;
               else
                     l=mid;
          }
          sum+=(r-1);
      }
    return sum;
}
int main()
{
    int s;
     scanf("%d",&s);
    while(s--)
    {
        scanf("%lld %lld",&n,&m);
        r=1e12;l=-1e12;
        while(r-l>1)
        {
            mid=(l+r)>>1;
            if(ok(mid)>=m)
                r=mid;
            else
                l=mid;
        }
        printf("%lld\n",r-1);
    }
    return 0;
}
注意
这个题非常容易错
这个代码 ,很绝望很绝望很绝望
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值