题目链接:https://codeforces.com/problemset/problem/1814/B
题目大意
有一个无限大的二维平面,我们用 \((x, y)\) 来表示平面中横坐标为 \(x\) 纵坐标为 \(y\) 的那个位置。
一个机器人被放置在该二维平面的 \((0, 0)\) 位置中。该机器人的腿长可以调节。最初,它的腿长为 \(1\) 。
假设机器人当前位于 \((x, y)\) 位置,其腿长为 \(m\) 。在一次移动中,它可以执行以下三个动作之一:
- 跳到 \((x + m, y)\) 位置;
- 跳到 \((x, y + m)\) 位置;
- 将腿的长度增加 \(1\) ,即将其腿长设置为 \(m + 1\) 。
求:机器人到达 \((a, b)\) 位置格的最小移动次数是多少?
题解
首先,我们考虑最终(即机器人到达 \((a, b)\) 时)机器人的腿长。
我们设机器人最终的腿长为 \(k\)。
这也就是说,在整个过程中,经历了机器人的腿长为 \(1, 2, 3, \ldots, k\) 的所有时刻。
为了方便表述,我们将题目里提到的三种操作分别称为 操作1、操作2 和 操作3,即:
- 操作1:跳到 \((x + m, y)\) 位置;
- 操作2:跳到 \((x, y + m)\) 位置;
- 操作3:将腿的长度增加 \(1\) ,即将其腿长设置为 \(m + 1\) 。
如果当前腿长为 \(m\),选择操作1,横坐标会增加 \(m\),选择操作2,纵坐标会增加 \(m\)。
我们可以将横坐标和纵坐标单独分析。
对于最终的横坐标 \(a\),在确定最终的腿长 \(k\) 的情况下,其实就是计算最少需要几个加数满足这些加数之和恰好为 \(a\),同时每个加数都不超过 \(k\)。很明显加数的数量最少为 \(\lceil \frac{a}{k} \rceil\) 个(这里 \(\lceil x \rceil\) 表示 \(x\) 向上取整)。
同理,我们可以得到,要按同样的方式得到 \(b\),加数的数量最少为 \(\lceil \frac{b}{k} \rceil\) 个。
这也就是说,在机器人最终的腿长为 \(k\) 的情况下:
- 操作1会执行 \(\lceil \frac{a}{k} \rceil\) 次;
- 操作2会执行 \(\lceil \frac{b}{k} \rceil\) 次;
- 操作3会执行 \(k-1\) 次(腿长从 \(1\) 增加到 \(k\) 需要 \(k - 1\) 次操作3)。
总的操作次数为 \(\lceil \frac{a}{k} \rceil + \lceil \frac{b}{k} \rceil + (k - 1)\)。
所以我们可以枚举 \(k\),然后求 \(\lceil \frac{a}{k} \rceil + \lceil \frac{b}{k} \rceil + (k - 1)\) 的最小值,即为答案。
\(k\) 的上限取为 \(\max(a, b)\) 的话,总的时间复杂度是 \(O(t \max(a, b))\),会超时。
但是考虑到,当 \(k \gt \sqrt{a}\) 时,相加得到 \(a\) 所需的加数不会超过 \(\sqrt{a}\) 个,所以 \(k\) 超过 \(2 \sqrt{a}\) 肯定不是最优解了,我那其中一般的操作3改为操作1,就能让横坐标变为 \(a\) 了。
所以,只需从 \(1\) 到 \(\sqrt{ \max(a, b) }\) 去枚举 \(k\),然后求操作次数的最小值即可(代码实现时为了方便起见给 \(k\) 开到 \(10^5\),因为 \(10^5\) 肯定大于 \(\sqrt{ \max(a, b) }\),同时也不会超时,所以也是没有问题的)。
示例程序:
#include <bits/stdc++.h>
using namespace std;
int cal(int a, int b) {
int res = a + b;
for (int k = 2; k <= 1e5; k++) {
int tmp = (k - 1) + (a - 1) / k + 1 + (b - 1) / k + 1;
res = min(res, tmp);
}
return res;
}
int t, a, b;
int main() {
cin >> t;
while (t--) {
cin >> a >> b;
cout << cal(a, b) << endl;
}
return 0;
}
标签:lceil,CF1814B,题解,机器人,加数,操作,frac,Legs,rceil
From: https://www.cnblogs.com/quanjun/p/18464535