本题看似是一个全排列搜索问题,但 的规模直接否定了暴力枚举的可能性( 是天文数字)。问题的本质是最小化最大值(Min-Max),这是典型的贪心算法应用场景。我们需要寻找一种局部最优的排序策略,使得其能够直接推导出全局最优解。

算法推导(微扰分析法)

为了确定大臣们的排序规则,我们采用“邻项交换法”(Exchange Argument)进行严格推导。

假设与推导

假设最优序列中,有两位相邻的大臣:大臣 排在前面,大臣 排在后面。 设他们之前所有人的左手数字乘积为 (是一个常数)。 大臣 的左右手数字为 ,大臣 的为

方案 A:顺序为

  • 大臣 获得的金币:
  • 大臣 获得的金币:
  • 该方案下的局部最大值:

方案 B:交换顺序为

  • 大臣 获得的金币:
  • 大臣 获得的金币:
  • 该方案下的局部最大值:

比较分析 我们的目标是让最大值尽可能小。假设方案 A 优于方案 B,即 。 由于 ,容易观察到:

  1. 在方案 A 中, 显然通常大于 (除非 极大, 极小,但即使如此,我们也关注主导项)。

  2. 严格推导时,我们可以比较 。去除公因子 ,我们比较:

  3. 两边同时乘以 去分母: 比较

    由于通常 ,则 。 因此,比较实际上简化为比较各自乘积项的主导地位:

    若我们要使得 ,则需要:

结论

为了使获得最多金币的大臣拿到的金币最少,应该将所有大臣按照 左右手数字之积 从小到大 进行排序。积越小的排在越前面。

代码实现

#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;
}