题目链接:http://poj.org/problem?id=3685
题意:说的很明确了。
思路:
很经典的二分套二分,通过观察表达式我们可以发现当j一定的时候,原表达式的值是跟i相关并且是单调的,所以我们可以二分答案m,然后统计比m小的数有多少个,在统计的时候需要先枚举j,然后再二分i,统计完成后,还需要判断这个结果是否存在(即是否存在i,j使表达式的值等于m),为此我的做法是在统计<=m的数,如果<=m的数的个数大于<m的数则这个结果是存在的。
整个算法的复杂度是O(n*logn*longn) 这种二分再二分的思路是非常经典的~~~~。
code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#define INF 10000005000
using namespace std;
typedef long long LL;
LL N,M;
LL cal(LL a,LL b)
{
return a*a+100000*a+b*b-100000*b+a*b;
}
bool judge(LL k)
{
LL res=0;
for(int j=1;j<=N;j++){
LL st=0,ed=N+1;
while(ed-st>1){
LL mid=(st+ed)/2;
if(cal(mid,j)>=k) ed=mid;
else st=mid;
}
res+=st;
if(res>=M) return true;
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&N,&M);
LL s=-(3*N*N+200000*N),t=3*N*N+200000*N;
while(t-s>1){
LL mid=(s+t)/2;
if(judge(mid)) t=mid;
else{
s=mid;
}
}
printf("%lld\n",s);
}
return 0;
}