poj3685 Matrix---两次二分

题目链接:https://vjudge.net/problem/POJ-3685

题意:N阶方阵第i行,j列的值Aij =i2+100000×i+j2-100000×j+i×j,求这个方阵的第M小值

二分答案mid,如果直接O(n^2)暴力check会tle。观察到Aij对于i是递增的,对于j则没有单调性。那么判断有多少个数<=mid的过程中,可以枚举列数j。对于每个j,利用单调性二分求出有多少个i满足Aij<=mid,这样check的复杂度就降为O(nlogn)

#include<iostream>
#define ll long long
using namespace std;

ll n,m,t,mid,lo,hi;
ll calc(ll p,ll q){return p*p+1e5*p+q*q-1e5*q+p*q;}

bool check(ll mid){
	ll tot=0; ll l,r;
	for (ll j=1;j<=n;j++){
	  if (calc(n,j)<=mid) tot+=n;
	  else {
	  	if (calc(1,j)>mid) continue;
	  	l=1;r=n;
	  	while (r-l>1){
	  	  ll mid2=(l+r)/2;
		  if (calc(mid2,j)>mid) r=mid2;else l=mid2;	
		}
		tot+=l;
	  }
	}
	return tot>=m;
}

int main(){
	cin>>t;
	while (t--){
	  cin>>n>>m;
	  lo=-1e10; hi=1e11;
	  while (hi-lo>1){
	  	mid=(lo+hi)/2;
	  	if (check(mid)) hi=mid;else lo=mid;
	  }
	  cout<<hi<<endl;
	}
} 

  

上一篇:rust thread


下一篇:一月5日