1. 程式人生 > >Atcoder 700 Worst Case 貪心+二分

Atcoder 700 Worst Case 貪心+二分

題意:兩個1,2,3,....inf的集合A,B. 從兩個集合中各選一個數(a,b)的得分為a*b.
Q次詢問,每次詢問(a,b),[表示分別選中a,b].問從剩下的兩個集合中最多能選出多少對(x,y)使得x*y<a*b  
Q<=100. 1<=a,b<=1e9.


當a<b
1,2,3,....a-1,a,a+1.....
1,2,3..C.............b,b+1......

(a+1)*(b+1)>ab , a<b時 (a-i)*(b+i)=ab+ai-bi-i*i < ab 所以讓[1..a-1]和[b+1...]匹配.
[a+1..]這部分顯然只能在b之前匹配 並且也是第i小的第i大匹配.

二分一個c 要找到 max(i*(a+c-i+1))[i=1..c] 中的最大值是否<ab 

因為是二次函式 在極點附近列舉一下即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll Q,a,b;
bool check(ll c)
{
	//f[x]=-x^2+(a+c+1)*x 
	ll A=-1,B=(a+c+1);
	ll po=-B/(2ll*A);
	//cout<<po<<'\n';
	for(ll i=max(1ll,po-500);i<=min(c,po+500);i++)
	{
		if(i*(a+c-i+1)>=a*b)
			return false;
	}
	return true;
}

int main()
{	
	cin>>Q;
	while(Q--)
	{
		cin>>a>>b;
		if(a>b)
			swap(a,b);
		ll l=1,r=b,p;
		while(l<=r)
		{
			ll mid=l+r>>1;
			if(check(mid))
				l=mid+1,p=mid;
			else
				r=mid-1;
		}
		ll res=a-1+p;	
		cout<<res<<'\n';
	}	
	return 0;
}