1 条题解

  • 0
    @ 2024-9-15 8:57:54

    算法: 贪心 时间复杂度 : O(n2)O(n^2)

    我们先给出做法,再证明其正确性。

    做法:直接将所有大臣按左右手上的数的乘积从小到大排序,得到的序列就是最优排队方案。

    证明:

    我们记第 ii 个大臣左手上的数是 AiA_i,右手上的数是 BiB_i
    假设当前的排队方案不是按 AiBiA_i * B_i 从小到大排序的,则一定存在某两个相邻的人,满足 AiBi>Ai+1Bi+1A_i * B_i > A_{i+1} * B_{i+1}
    我们现在将这两个人的位置互换,然后考虑他们在交换前和交换后所获得的奖励是多少:

    • 交换前:第 ii 个人是 j=0i1AjBi\frac{\prod_{j=0}^{i-1}A_j}{B_i},第 i+1i + 1 个人是 j=0iAjBi+1\frac{\prod_{j=0}^{i}A_j}{B_{i + 1}};
    • 交换后:第 ii 个人是 j=0i1AjBi+1\frac{\prod_{j=0}^{i-1}A_j}{B_{i + 1}},第 i+1i + 1 个人是 Ai+1j=0i1AjBi\frac{A_{i + 1} * \prod_{j=0}^{i - 1}A_j}{B_i};

    由于我们接下来只比较这四个数的大小关系,而且所有 Ai,BiA_i, B_i 均大于0,所以可以将每个数除以 j=0i1Aj\prod_{j=0}^{i-1}A_j,然后乘 BiBi+1B_i * B_{i + 1},得到:

    ii 个人 i+1i + 1 个人
    交换前 Bi+1B_{i + 1} AiBiA_i * B_i
    交换后 BiB_i Ai+1Bi+1A_{i + 1} * B_{i + 1}

    由于 Ai>0A_i > 0,所以 BiAiBiB_i \le A_i * B_i,并且 AiBi>Ai+1Bi+1A_i * B_i > A_{i+1} * B_{i+1},所以 $max(B_i, A_{i + 1} * B_{i + 1}) \le A_i * B_i \leq max(B_{i + 1}, A_i * B_i)$, 所以交换后两个数的最大值不大于交换前两个数的最大值。
    而且交换相邻两个数不会对其他人的奖金产生影响,所以如果存在逆序,则将其交换,得到的结果一定不会比原来更差。

    所以从小到大排好序的序列就是最优解,证毕。

    时间复杂度

    排序的时间复杂度是 O(nlogn)O(nlogn)
    这道题目的时间复杂度瓶颈在高精度计算上,最坏情况下所有 Ai=9999A_i = 9999,则前 ii 个数的乘积大约是 4i4i 位,每次乘一个新的数就需要 4i4i 的计算量,所以总共的计算量是 O(4i=1ni)=O(n2)O(4 * \sum_{i = 1}^ni) = O(n^2)

    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    typedef pair<int, int> PII;
    const int N = 1010;
    
    int n;
    PII p[N];
    
    vector<int> mul(vector<int>a, int b)
    {
        vector<int> c;
        int t = 0;
        for (int i = 0; i < a.size(); i ++ )
        {
            t += a[i] * b;
            c.push_back(t % 10);
            t /= 10;
        }
        while (t)
        {
            c.push_back(t % 10);
            t /= 10;
        }
        return c;
    }
    
    vector<int> div(vector<int>a, int b)
    {
        vector<int> c;
        bool is_first = true;
        for (int i = a.size() - 1, t = 0; i >= 0; i -- )
        {
            t = t * 10 + a[i];
            int x = t / b;
            if (!is_first || x)
            {
                is_first = false;
                c.push_back(x);
            }
            t %= b;
        }
        reverse(c.begin(), c.end());
        return c;
    }
    
    vector<int> max_vec(vector<int> a, vector<int> b)
    {
        if (a.size() > b.size()) return a;
        if (a.size() < b.size()) return b;
        if (vector<int>(a.rbegin(), a.rend()) > vector<int>(b.rbegin(), b.rend())) return a;
        return b;
    }
    
    int main()
    {
        cin >> n;
        for (int i = 0; i <= n; i ++ )
        {
            int a, b;
            cin >> a >> b;
            p[i] = {a * b, a};
        }
        sort(p + 1, p + n + 1);
    
        vector<int> product(1, 1);
    
        vector<int> res(1, 0);
        for (int i = 0; i <= n; i ++ )
        {
            if (i) res = max_vec(res, div(product, p[i].first / p[i].second));
            product = mul(product, p[i].second);
        }
    
        for (int i = res.size() - 1; i >= 0; i -- ) cout << res[i];
        cout << endl;
    
        return 0;
    }
    

    信息

    ID
    5
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    (无)
    递交数
    91
    已通过
    8
    上传者