题目链接

题目描述

国王左、右手分别写下两个整数 ;共有 位大臣,第 位大臣左、右手写下 。国王站最前,其余大臣可任意排序。若某位大臣在队列中的相对位置为 ,则他获得的金币数为

其中 为队列中大臣的编号顺序。目标是通过调整大臣顺序,使“获得金币最多的大臣”的金币数尽可能小,并输出该最小值。

(本题为简化版, 不参与计算,仅作为题面设定。)

解题思路

  • 记前缀乘积 。第 位大臣的金币为
  • 只需最小化 。对任意相邻两位大臣 ,比较先后次序对“二者的最坏值”的影响,可得应按 的升序排序(交换论证标准结论)。
  • 排序后,从前到后维护前缀乘积 ,依次计算 的最大值,并在每步将
  • 为避免溢出: 可能很大,需用“大整数”维护;计算时只涉及“乘以 ”与“除以 ”。

代码

#include <bits/stdc++.h>
using namespace std;

// 简易大整数(非负),基数 1e9,支持:乘以 int、除以 int(取整商)、比较、输出
struct BigInt {
    static const int BASE = 1000000000;
    vector<int> d; // 低位在前
    BigInt(long long x = 0) { *this = x; }
    BigInt& operator=(long long x) {
        d.clear();
        if (x == 0) return d.push_back(0), *this;
        while (x) { d.push_back(int(x % BASE)); x /= BASE; }
        return *this;
    }
    void trim() { while (d.size() > 1 && d.back() == 0) d.pop_back(); }
    string toString() const {
        if (d.empty()) return "0";
        string s = to_string(d.back());
        for (int i = (int)d.size() - 2; i >= 0; --i) {
            string t = to_string(d[i]);
            s += string(9 - t.size(), '0') + t;
        }
        return s;
    }
};

static inline bool operator<(const BigInt& a, const BigInt& b) {
    if (a.d.size() != b.d.size()) return a.d.size() < b.d.size();
    for (int i = (int)a.d.size() - 1; i >= 0; --i) if (a.d[i] != b.d[i]) return a.d[i] < b.d[i];
    return false;
}
static inline bool operator>(const BigInt& a, const BigInt& b) { return b < a; }

static inline void mul_int(BigInt& a, int m) {
    if (m == 0) { a = 0; return; }
    long long carry = 0;
    for (size_t i = 0; i < a.d.size(); ++i) {
        long long cur = carry + 1LL * a.d[i] * m;
        a.d[i] = int(cur % BigInt::BASE);
        carry = cur / BigInt::BASE;
    }
    while (carry) { a.d.push_back(int(carry % BigInt::BASE)); carry /= BigInt::BASE; }
}

static inline BigInt div_int(const BigInt& a, int v) { // 商
    BigInt q; q.d.assign(a.d.size(), 0);
    long long rem = 0;
    for (int i = (int)a.d.size() - 1; i >= 0; --i) {
        long long cur = a.d[i] + rem * BigInt::BASE;
        q.d[i] = int(cur / v);
        rem = cur % v;
    }
    q.trim();
    return q;
}

struct Node { int l, r; };

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n; if (!(cin >> n)) return 0;
    long long L0, R0; cin >> L0 >> R0; // R0 不使用
    vector<Node> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i].l >> a[i].r;

    sort(a.begin(), a.end(), [](const Node& x, const Node& y){
        long long X = 1LL * x.l * x.r;
        long long Y = 1LL * y.l * y.r;
        if (X != Y) return X < Y;
        return x.l < y.l; // 次关键字任意,稳定性无关最优性
    });

    BigInt pref(L0);      // 当前前缀乘积 P
    BigInt answer(0);     // 当前最小化后的“最大金币数”
    for (int i = 0; i < n; ++i) {
        BigInt gain = div_int(pref, a[i].r); // floor(P / r_i)
        if (gain > answer) answer = gain;
        mul_int(pref, a[i].l);               // P *= l_i
    }

    cout << answer.toString() << '\n';
    return 0;
}
import java.util.*;
import java.math.*;

public class Main {
    static class Node { int l, r; Node(int l, int r){ this.l=l; this.r=r; } }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        long L0 = sc.nextLong(), R0 = sc.nextLong(); // R0 不使用
        Node[] arr = new Node[n];
        for (int i = 0; i < n; i++) arr[i] = new Node(sc.nextInt(), sc.nextInt());
        Arrays.sort(arr, (x, y) -> {
            long X = 1L * x.l * x.r;
            long Y = 1L * y.l * y.r;
            if (X != Y) return Long.compare(X, Y);
            return Integer.compare(x.l, y.l);
        });

        BigInteger pref = BigInteger.valueOf(L0);
        BigInteger ans = BigInteger.ZERO;
        for (Node e : arr) {
            BigInteger gain = pref.divide(BigInteger.valueOf(e.r));
            if (gain.compareTo(ans) > 0) ans = gain;
            pref = pref.multiply(BigInteger.valueOf(e.l));
        }
        System.out.println(ans.toString());
    }
}
n = int(input())
L0, R0 = map(int, input().split())  # R0 不使用
arr = [tuple(map(int, input().split())) for _ in range(n)]

arr.sort(key=lambda x: x[0] * x[1])

pref = L0
ans = 0
for l, r in arr:
    gain = pref // r
    if gain > ans:
        ans = gain
    pref *= l

print(ans)

算法及复杂度

  • 算法:按 升序排序,线性扫描维护前缀乘积 ,在每一步计算 的最大值,最后输出该最大值。
  • 时间复杂度:排序 ,扫描 ;大整数乘除的常数与位数有关,整体可通过本题数据通过。
  • 空间复杂度(存边与排序,中间使用大整数)。