CF1814B

发布时间 2023-10-13 21:30:01作者: 悲伤鳄鱼吃面包

Long Legs

题面翻译

给你一个无限大小的棋盘,一个机器人初始位置为 \((0,0)\),初始每次可移动的长度为 \(1\)
对于一个当前在 \((x,y)\) 的机器人,且它当前的可移动长度为 \(m\)(初始为 \(1\))。则它可以耗费一个时间进行如下操作:
\(\qquad\) 1. 移动到 \((x+m,y)\)
\(\qquad\) 2. 移动到 \((x,y+m)\)
\(\qquad\) 3.使得 \(m=m+1\)
注意:在当前位置使得 \(m=m+1\) 后会影响后面的操作。

现在给你两个正整数 \(a,b(1 \leq a,b \leq 10^9)\),问机器人最少需要多少单位时间可以到达 \((a,b)\)

题目描述

A robot is placed in a cell $ (0, 0) $ of an infinite grid. This robot has adjustable length legs. Initially, its legs have length $ 1 $ .

Let the robot currently be in the cell $ (x, y) $ and have legs of length $ m $ . In one move, it can perform one of the following three actions:

  • jump into the cell $ (x + m, y) $ ;
  • jump into the cell $ (x, y + m) $ ;
  • increase the length of the legs by $ 1 $ , i. e. set it to $ m + 1 $ .

What's the smallest number of moves robot has to make to reach a cell $ (a, b) $ ?

输入格式

The first line contains a single integer $ t $ ( $ 1 \le t \le 100 $ ) — the number of test cases.

The only line of each test case contains two integers $ a $ and $ b $ ( $ 1 \le a, b \le 10^9 $ ) — the ending cell.

输出格式

For each test case, print a single integer — the smallest number of moves the robot is required to make to reach a cell $ (a, b) $ from a cell $ (0, 0) $ .

样例 #1

样例输入 #1

3
1 1
1 6
8 4

样例输出 #1

2
5
6

提示

In the first testcase, the robot can first jump to $ (0, 1) $ , then to $ (1, 1) $ . If it ever increases the length of its legs, it will only be able to jump past $ (1, 1) $ .

In the second testcase, the robot can jump to $ (1, 0) $ , then increase the length of its length to $ 2 $ and jump three times to reach $ (1, 6) $ .

In the third testcase, the robot can increase the length of its legs three times to make it $ 4 $ . Then jump to $ (0, 4) $ . Then jump twice to reach $ (8, 4) $ .

分析

第三种操作进行次数太少时, m 太小, 需要的时间就会增加, 但如果 m 过大, 第三种操作浪费了太多的步数, 也会导致时间边长

我们的策略是: 先选好一个合适的 m , 然后以这个 m 来跳格子

终点是 (a, b) , 以x轴为例:

  • 当 a 可以被我们选好的 m 整除时, 跳到 (a, 0) 的步数是 \(\frac{a}{m}\) ,
  • 当 a 不能被整除时, 我们以 m 去跳最多能跳到 \(\left [ \frac{a}{m}\right ]\) 位置, 剩下的部分一定小于 m , 记为 k , 我们在增加步长的过程中肯定会出现 m = k 的时候, 我们只需要在这个时候以步长 k 跳一次格子即可, 跳到 (a, 0) 的步数就是 \(\left [ \frac{a}{m}\right ] + 1\)

对于y轴同理, 能整除就是 \(\frac{b}{m}\) , 不能整除就是 \(\left [ \frac{b}{m}\right ] + 1\)

再加上增加步长需要的操作次数 (m - 1) , 总的操作次数就是: \(x到a的步数 + y到b的步数 + (m - 1)\)

我们只需要1开始枚举合适的步长 m , m 最大是不会超过 \(3 \times 10^5\)

为什么 m 最大不超过 \(3 \times 10^5\) 呢?

我们发现, a和b均不能被m整除时的总操作次数 和 a和b均可以被m整除的总操作次数之间也就差2, 随便选一种来讨论

已知: \(m + n \le 2 \sqrt{mn}\) , 当且仅当 \(m = n\) 时取到等于号

那么对于总操作次数来说有 \(\frac{a + b}{m} + m - 1\le 2\sqrt{\frac{a + b}{m}}-1\) , 要想操作次数取最小, 即是 \(\frac{a+b}{m} = m\) , 即\(m = \sqrt{a+b}\)

当 a = b = \(10^9\) 时, m不过也就是 \(\sqrt{2} \times 10^\frac{9}{2}\) , 是不会超时的

代码

#include <iostream>
using namespace std;
const int N = 3e5;
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

	int t; cin >> t;
	while (t--)
	{
		int a, b; cin >> a >> b;
		
		int ans = N;
		for (int i = 1; i <= N; i++)
		{
			int t = (a / i) + (a % i != 0) + (b / i) + (b % i != 0) + i - 1;
			ans = min(ans, t);
		}
		cout << ans << endl;
	}
}