题意
可以选择在一回合中增长腿长 1,也可以选择在 x 轴或 y 轴增加当前腿长,问最少多少回合达到坐标 (a,b)
思路
首先容易想到升级的顺序是无关的,即你可以达到一个腿长 x ,那么对于 a b,一定只需要 a/x + 1(if a % x != 0), b/x + 1(if b % x != 0)
但是 x 枚举多少呢?一开始看数据范围直觉感觉是枚举到 sqrt(max(a,b)) ,后来为wa
怀疑是三分,补了个三分还是wa
打表看了下,把sqrt(max(a,b)) 开 2 倍常数就能过
题解里说了 根据导数证明其实是 根号2 常数
#include<cstdio>
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
int check(int a,int b,int tmp)
{
if(tmp==0) return a + b;
int cost = 0;
if(a%tmp!=0) cost++;
if(b%tmp!=0) cost++;
return cost + (a / tmp) + (b / tmp);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int a,b,ans;
scanf("%d%d",&a,&b);
ans = a + b;
for(int i = 1;i<=sqrt(a)*sqrt(2)+1;++i)
{
ans = min(ans,check(a,b,i)+i-1) ;
if(a/i>=1) ans = min(ans,check(a,b,a/i)+a/i-1);
}
for(int i = 1;i<=sqrt(b)*sqrt(2)+1;++i)
{
ans = min(ans,check(a,b,i)+i-1);
if(b/i>=1) ans = min(ans,check(a,b,b/i)+b/i-1);
}
// int l = 1, r = max(a,b);
// while(l<=r)
// {
// int init_l = l, init_r = r;
// int m1 = l + (r-l) / 3;
// int m2 = r - (r-l) / 3;
// ans = min(ans,check(a,b,m1)+m1-1);
// ans = min(ans,check(a,b,m2)+m2-1);
// if(check(a,b,m1)+m1-1 > check(a,b,m2)+m2-1) l = m1;
// else r = m2;
// if(l==init_l && r == init_r) break;
// }
// for(int i = l;i<=r;++i) ans = min(ans,check(a,b,i)+i-1);
printf("%d\n",ans);
}
return 0;
}