题目
4956. 冶炼金属 - AcWing题库
蓝桥杯2023年第十四届省赛真题-冶炼金属 - C语言网
小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X 。
这个炉子有一个称作转换率的属性 V V V , V V V 是一个正整数,这意味着消耗 V V V 个普通金属 O O O 恰好可以冶炼出一个特殊金属 X X X ,当普通金属 O O O 的数目不足 V V V 时,无法继续冶炼。
现在给出了 N N N 条冶炼记录,每条记录中包含两个整数 A A A 和 B B B ,这表示本次投入了 A A A 个普通金属 O O O ,最终冶炼出了 B B B 个特殊金属 X X X 。
每条记录都是独立的,这意味着上一次没消耗完的普通金属 O O O 不会累加到下一次的冶炼当中。
根据这 N N N 条冶炼记录,请你推测出转换率 V V V 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况 。
输入格式
第一行一个整数 N N N ,表示冶炼记录的数目。
接下来输入 N N N 行,每行两个整数 A 、 B A、B A 、 B ,含义如题目所述。
输出格式
输出两个整数,分别表示 V V V 可能的最小值和最大值,中间用空格分开。
数据范围
对于 30 % 30\% 3 0 % 的评测用例, 1 ≤ N ≤ 1 0 2 1 ≤ N ≤ 10^2 1 ≤ N ≤ 1 0 2 。
对于 60 % 60\% 6 0 % 的评测用例, 1 ≤ N ≤ 1 0 3 1 ≤ N ≤ 10^3 1 ≤ N ≤ 1 0 3 。
对于 100 % 100\% 1 0 0 % 的评测用例, 1 ≤ N ≤ 1 0 4 1 ≤ N ≤ 10^4 1 ≤ N ≤ 1 0 4 , 1 ≤ B ≤ A ≤ 1 0 9 1 ≤ B ≤ A ≤ 10^9 1 ≤ B ≤ A ≤ 1 0 9 。
输入样例:
3
75 3
53 2
59 2
输出样例:
20 25
样例解释
当 V = 20 V = 20 V = 2 0 时,有: ⌊ 75 20 ⌋ = 3 ⌊\frac{75}{20} ⌋ = 3 ⌊ 2 0 7 5 ⌋ = 3 , ⌊ 53 20 ⌋ = 2 ⌊\frac{53}{20} ⌋ = 2 ⌊ 2 0 5 3 ⌋ = 2 , ⌊ 59 20 ⌋ = 2 ⌊\frac{59}{20} ⌋ = 2 ⌊ 2 0 5 9 ⌋ = 2 ,可以看到符合所有冶炼记录。
当 V = 25 V = 25 V = 2 5 时,有: ⌊ 75 25 ⌋ = 3 ⌊\frac{75}{25} ⌋ = 3 ⌊ 2 5 7 5 ⌋ = 3 , ⌊ 53 25 ⌋ = 2 ⌊\frac{53}{25} ⌋ = 2 ⌊ 2 5 5 3 ⌋ = 2 , ⌊ 59 25 ⌋ = 2 ⌊\frac{59}{25} ⌋ = 2 ⌊ 2 5 5 9 ⌋ = 2 ,可以看到符合所有冶炼记录。
且再也找不到比 20 20 2 0 更小或者比 25 25 2 5 更大的符合条件的 V V V 值了。
解题
方法一:二分查找
思路
由题意可知,我们需要找出 V m i n V_{min} V m i n 与 V m a x V_{max} V m a x ,使得 ⌊ A i V ⌋ = B i \lfloor \frac{A_i}{V} \rfloor = B_i ⌊ V A i ⌋ = B i (其中 i = 1 … N , V ∈ [ V m i n , V m a x ] i = 1\dots{N}, \enspace V \in[V_{min}, V_{max}] i = 1 … N , V ∈ [ V m i n , V m a x ] )。
由于每条冶炼记录都是独立的,要使所有冶炼记录都成立, V V V 的范围就应是所有 V i V_i V i 的交集,也就是说: V m i n = max ( V 1 m i n , V 2 m i n , … , V N m i n ) , V m a x = min ( V 1 m a x , V 2 m a x , … , V N m a x ) V_{min} = \max(V_{1_{min}}, V_{2_{min}}, \dots, V_{N_{min}}), \enspace V_{max} = \min(V_{1_{max}}, V_{2_{max}}, \dots, V_{N_{max}}) V m i n = max ( V 1 m i n , V 2 m i n , … , V N m i n ) , V m a x = min ( V 1 m a x , V 2 m a x , … , V N m a x ) 。
对于第 i i i 条冶炼记录,A i V i \frac{A_i}{V_i} V i A i 是单调的( V i ↑ , A i V i ↓ V_i \uparrow, \frac{A_i}{V_i} \downarrow V i ↑ , V i A i ↓ ),所以 V i V_i V i 的上界与下界可以借助二分查找 找出来。
代码
#include <iostream>
using namespace std;
int n, a, b;
int main() {
scanf("%d", &n);
int vmn = 1, vmx = 2e9;
while (n--) {
scanf("%d%d", &a, &b);
int l = 1, r = 2e9;
while (l < r) {
int m = l + (r - l >> 1);
if (a / m <= b) r = m;
else l = m + 1;
}
vmn = max(vmn, l);
l = 1, r = 2e9;
while (l < r) {
int m = l + (r - l + 1 >> 1);
if (a / m >= b) l = m;
else r = m - 1;
}
vmx = min(vmx, r);
}
printf("%d %d\n", vmn, vmx);
return 0;
}
方法二:数学
思路
V i V_i V i 的上界和下界也可以通过公式直接算出来。
⌊ A i V i ⌋ = B i ⟹ A i V i ∈ [ B i , B i + 1 ) ⟹ B i ≤ A i V i < B i + 1 ⟹ A i B i + 1 < V i ≤ A i B i ⟹ V i m a x = ⌊ A i B i ⌋ , V i m i n = { A i B i + 1 + 1 A i B i + 1 ∈ Z ⌈ A i B i + 1 ⌉ A i B i + 1 ∉ Z ⟹ V i m a x = ⌊ A i B i ⌋ , V i m i n = ⌊ A i B i + 1 ⌋ + 1 \begin{aligned}
\lfloor \frac{A_i}{V_i} \rfloor = B_i &\Longrightarrow \frac{A_i}{V_i} \in [B_i, B_i + 1) \\
&\Longrightarrow B_i \le \frac{A_i}{V_i} < B_i + 1 \\
&\Longrightarrow \frac{A_i}{B_i + 1} < V_i \le \frac{A_i}{B_i} \\
&\Longrightarrow V_{i_{max}} = \lfloor \frac{A_i}{B_i} \rfloor, \enspace V_{i_{min}} =
\begin{cases}
\frac{A_i}{B_i + 1} + 1 & \frac{A_i}{B_i + 1} \in \mathbb{Z} \\
\lceil \frac{A_i}{B_i + 1} \rceil & \frac{A_i}{B_i + 1} \notin \mathbb{Z}
\end{cases} \\
&\Longrightarrow V_{i_{max}} = \lfloor \frac{A_i}{B_i} \rfloor, \enspace V_{i_{min}} = \lfloor \frac{A_i}{B_i + 1} \rfloor + 1
\end{aligned}
⌊ V i A i ⌋ = B i ⟹ V i A i ∈ [ B i , B i + 1 ) ⟹ B i ≤ V i A i < B i + 1 ⟹ B i + 1 A i < V i ≤ B i A i ⟹ V i m a x = ⌊ B i A i ⌋ , V i m i n = { B i + 1 A i + 1 ⌈ B i + 1 A i ⌉ B i + 1 A i ∈ Z B i + 1 A i ∈ / Z ⟹ V i m a x = ⌊ B i A i ⌋ , V i m i n = ⌊ B i + 1 A i ⌋ + 1
代码
#include <iostream>
using namespace std;
int n, a, b;
int main() {
scanf("%d", &n);
int vmn = 1, vmx = 2e9;
while (n--) {
scanf("%d%d", &a, &b);
vmn = max(vmn, a / (b + 1) + 1);
vmx = min(vmx, a / b);
}
printf("%d %d\n", vmn, vmx);
return 0;
}
评论区