1. 程式人生 > 其它 >P1080 國王遊戲題解

P1080 國王遊戲題解

題目傳送門

我們對於國王身後的兩個點來分析

佇列可能是這樣的:

\(*\) 左手 右手
國王 \(a_0\) \(b_0\)
\(p1\) \(a_1\) \(b_1\)
\(p2\) \(a_2\) \(b_2\)

根據題意:每位大臣獲得的金幣數分別是:排在該大臣前面的所有人的左手上的數的乘積除以他自己右手上的數,然後向下取整得到的結果。

那麼我們計算可得當前情況下大臣的最大金幣數量: \(\large ans_1=max(\frac{a_0}{b_1},\frac{a_0*a_1}{b_2})\)

佇列也有可能是這樣的

\(*\) 左手 右手
國王 \(a_0\)
\(b_0\)
\(p2\) \(a_2\) \(b_2\)
\(p1\) \(a_1\) \(b_1\)

那麼我們計算可得 \(\large ans_2=max(\frac{a_0}{b_2},\frac{a_0*a_2}{b_1})\)

我們來對比一下兩個答案:
\(ans_1=max(\frac{a_0}{b_1},\frac{a_0 * a_1}{b_2})\)
\(ans_2=max(\frac{a_0}{b_2},\frac{a_0 * a_2}{b_1})\)


\(k_1=\frac{a_0}{b_1}\)
\(k_2=\frac{a_0 * a_1}{b_2}\)
\(k_3=\frac{a_0}{b_2}\)


\(k_4=\frac{a_0 * a_2}{b_1}\)

因為\(a_0*a_1>a_0\),所以 \(\frac{a_0 * a_1}{b_2}>\frac{a_0}{b_2}\),即 \(k_2>k_3\)

因為\(a_0*a_2>a_0\),所以 \(\frac{a_0 * a_2}{b_1}>\frac{a_0}{b_1}\),即 \(k_4>k_1\)

如果 \(ans_1<ans_2\),那麼得到 $ max(k_1,k_2) < max(k_3,k_4)$

所以 $k_4 > k_2 $

即: \(\frac{a_0 * a_2}{b_1}> \frac{a_0 * a_1}{b_2}\)

不等式變型

$ a_0 * a_2 * b_2 > a_0 * a_1 * b_1$

再消去\(a_0\)

$ a_2 * b_2 > a_1 * b_1$

也就是
$ a_1 * b_1 < a_2 * b_2$

也就是說,當 \(a_1 * b+1 < a_2 * b_2\)時,可以得到 \(ans_1 <ans_2\),也就是為了使\(ans\)更小,需要將$a_i * b_i \(較小的放在前面,我們以\) a_i * b_i $為關鍵字排序即可。

同時,由於資料範圍是:
\(n=1000\),同時 \(a<=10000\),連乘就是 100010000相乘,需要用到高精度。

C++ 程式碼

#include<bits/stdc++.h>

using namespace std;

const int N = 1010;
int n;
struct Person {
    int left, right;
} person[N];

bool cmp(const Person &a, const Person &b) {
    return a.left * a.right < b.left * b.right;
}

//高精度乘法
vector<int> mul(vector<int> &A, int b) {
    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size() || t; i++) {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

//高精度除法
vector<int> div(vector<int> &A, int b, int &r) {
    vector<int> C;
    r = 0;
    for (int i = A.size() - 1; i >= 0; i--) {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

//獲取兩個vector<int>中較大的那個
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++) cin >> person[i].left >> person[i].right;
    //排序
    sort(person + 1, person + n + 1, cmp);

    //隊伍中放入國王
    vector<int> sum(1, person[0].left);

    //結果
    vector<int> res(1, 0);
    int r;
    for (int i = 1; i <= n; i++) {
        res = max_vec(res, div(sum, person[i].right, r));
        sum = mul(sum, person[i].left);
    }
    //輸出
    for (int i = res.size() - 1; i >= 0; i--) cout << res[i];
}