本题看似是一个全排列搜索问题,但 的规模直接否定了暴力枚举的可能性(
是天文数字)。问题的本质是最小化最大值(Min-Max),这是典型的贪心算法应用场景。我们需要寻找一种局部最优的排序策略,使得其能够直接推导出全局最优解。
算法推导(微扰分析法)
为了确定大臣们的排序规则,我们采用“邻项交换法”(Exchange Argument)进行严格推导。
假设与推导
假设最优序列中,有两位相邻的大臣:大臣 排在前面,大臣
排在后面。
设他们之前所有人的左手数字乘积为
(是一个常数)。
大臣
的左右手数字为
,大臣
的为
。
方案 A:顺序为
- 大臣
获得的金币:
- 大臣
获得的金币:
- 该方案下的局部最大值:
方案 B:交换顺序为
- 大臣
获得的金币:
- 大臣
获得的金币:
- 该方案下的局部最大值:
比较分析
我们的目标是让最大值尽可能小。假设方案 A 优于方案 B,即 。
由于
,容易观察到:
-
在方案 A 中,
显然通常大于
(除非
极大,
极小,但即使如此,我们也关注主导项)。
-
严格推导时,我们可以比较
和
。去除公因子
,我们比较:
与
-
两边同时乘以
去分母: 比较
与
由于通常
,则
且
。 因此,比较实际上简化为比较各自乘积项的主导地位:
与
若我们要使得
,则需要:
结论
为了使获得最多金币的大臣拿到的金币最少,应该将所有大臣按照 左右手数字之积 从小到大 进行排序。积越小的排在越前面。
代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
int a0, b0;
cin >> a0 >> b0;
vector<int> a(n), b(n);
for (int i = 0; i < n; i++) {
cin >> a[i] >> b[i];
}
vector<int> ids(n);
iota(ids.begin(), ids.end(), 0);
sort(ids.begin(), ids.end(), [&](int i, int j) {
return a[i] * b[i] < a[j] * b[j];
});
ll prod = a0;
ll ans = 0;
for (int i = 0; i < n; i++) {
int idx = ids[i];
ans = max(ans, prod / b[idx]);
prod *= a[idx];
}
cout << ans << endl;
}

京公网安备 11010502036488号