标签:ack space value mes tps string iostream tmp 题意
有一个N
阶方阵,方正中第i
行第j
列的元素值为\(d_{i,j}=i^{2}+1e5*i+j^{2}-1e5*j+i*j\),我们需要找出这个方阵中第M
小的元素值。
分析这个公式,我们发现:当j
固定的时候,这个公式关于i
(取值范围:从0
到n
)是单调增加的,所以这里我们可以二分一个答案,然后一列一列的找小于(等于)它的个数,这样加起来我们就能知道我们枚举的这个答案是第几小了。
需要注意的是,第一个最外层的二分有点不同,因为我们二分的答案可能不存在,但是也是符合第m
小,这个情况还是需要注意的,这里需要参看关于二分的第四种形式。二分链接
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<map>
typedef long long ll;
using namespace std;
const double esp=1e-6;
const int inf=0x3f3f3f3f;
const int MAXN=1E6+7;
ll n, m;
ll fun(ll i, ll j)
{
return i*i+100000*i+j*j-100000*j+i*j;
}
void dis()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
printf("%lld ", fun(i, j));
}
printf("\n");
}
}
ll solve(ll value)
{
ll sum=0;
for(ll j=1; j<=n; j++)
{
ll left=0, right=n+1, ans=0;
while(left < right)
{
ll mid=left+(right-left)/2;
if(fun(mid, j) <= value)
left=mid+1;
else right=mid;
}
if(left!=0)
sum+=left-1;
}
return sum;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%lld%lld", &n, &m);
// dis();
ll lt=-1e12, rt=1e12, ans;
while(lt+1 < rt) //这里的二分我们提前是不知道该向左侧还是右侧前进的。
{
ll mid = lt + (rt-lt)/2;
ll tmp=solve(mid);
if(tmp >= m)
{
ans=mid;
rt=mid;
}
else lt=mid;
}
printf("%lld\n", ans);
}
return 0;
}
标签:ack space value mes tps string iostream tmp 题意
原文地址:https://www.cnblogs.com/alking1001/p/12257226.html