【ACWing】114. 国王游戏

题目地址:

https://www.acwing.com/problem/content/description/116/

恰逢某国国庆,国王邀请 n n n位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n n n位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入格式:
第一行包含一个整数 n n n,表示大臣的人数。第二行包含两个整数 a a a b b b,之间用一个空格隔开,分别表示国王左手和右手上的整数。接下来 n n n行,每行包含两个整数 a a a b b b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

输出格式:
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

数据范围:
1 ≤ n ≤ 1000 1≤n≤1000 1n1000
0 < a , b < 10000 0<a,b<10000 0<a,b<10000

按照 a ∗ b a*b ab从小到大排序然后枚举即可。

算法正确性证明:
对于某解,考虑第 i i i个大臣和第 i + 1 i+1 i+1个大臣,他们获得的金币数是 ( 1 b i ∏ k = 1 i − 1 a k , 1 b i + 1 ∏ k = 1 i a k ) (\frac{1}{b_i}\prod_{k=1}^{i-1}a_k,\frac{1}{b_{i+1}}\prod_{k=1}^{i}a_k) (bi1k=1i1ak,bi+11k=1iak),如果将这两个人交换位置,那么获得的金币是 ( 1 b i + 1 ∏ k = 1 i − 1 a k , 1 b i a i + 1 ∏ k = 1 i − 1 a k ) (\frac{1}{b_{i+1}}\prod_{k=1}^{i-1}a_k,\frac{1}{b_i}a_{i+1}\prod_{k=1}^{i-1}a_k) (bi+11k=1i1ak,bi1ai+1k=1i1ak)。显然交换这两个人的话,别的所有人的金币数都是不变的。我们把同类项去掉,看 ( 1 b i , a i b i + 1 ) (\frac{1}{b_i},\frac{a_i}{b_{i+1}}) (bi1,bi+1ai) ( 1 b i + 1 , a i + 1 b i ) (\frac{1}{b_{i+1}},\frac{a_{i+1}}{b_i}) (bi+11,biai+1),再同时乘以 b i b i + 1 b_ib_{i+1} bibi+1,比较 ( b i + 1 , a i b i ) (b_{i+1},a_ib_i) (bi+1,aibi) ( b i , a i + 1 b i + 1 ) (b_i,a_{i+1}b_{i+1}) (bi,ai+1bi+1)。如果 a i b i ≥ a i + 1 b i + 1 a_ib_i\ge a_{i+1}b_{i+1} aibiai+1bi+1,那么交换之后, max ⁡ { b i , a i + 1 b i + 1 } ≤ max ⁡ { b i + 1 , a i b i } \max\{b_i,a_{i+1}b_{i+1}\}\le \max\{b_{i+1},a_ib_i\} max{ bi,ai+1bi+1}max{ bi+1,aibi},也就是说交换之后结果不会变得更差。所以对于任意一个最优解,总能把它通过交换使得其是按照 a i b i a_ib_i aibi从小到大排序的,所以按照 a i b i a_ib_i aibi从小到大排序的就能得到最优解。排好序后只需要算一下每个大臣有多少金币,找到拿的金币最多的那个即可(需要高精度)。代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 1010;
pair<int, int> p[N];
int n;

vector<int> mul(vector<int> a, int b) {
    
    
    vector<int> c;
    for (int i = 0, t = 0; i < a.size() || t; i++) {
    
    
        if (i < a.size()) t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }

    return c;
}

vector<int> div(vector<int> a, int b) {
    
    
    vector<int> c;
    for (int i = a.size() - 1, t = 0; i >= 0; i--) {
    
    
        t = t * 10 + a[i];
        int d = t / b;
        if (d || !c.empty()) c.push_back(d);
        t %= b;
    }

    reverse(c.begin(), c.end());
    if (c.empty()) c.push_back(0);
    return c;
}

vector<int> maxv(vector<int> a, vector<int> b) {
    
    
    if (a.size() != b.size()) return a.size() > b.size() ? a : b;
    for (int i = a.size() - 1; i >= 0; i--) 
        if (a[i] != b[i]) return a[i] > b[i] ? a : b;

    return a;
}

int main() {
    
    
    cin >> n;
    cin >> p[0].first >> p[0].second;

    for (int i = 1; i <= n; i++) {
    
    
        int x, y;
        cin >> x >> y;
        p[i] = {
    
    x * y, y};
    }

    sort(p + 1, p + n + 1);

    vector<int> res(1, 0);
    vector<int> prod(1, 1);
    prod = mul(prod, p[0].first);

    for (int i = 1; i <= n; i++) {
    
    
        res = maxv(res, div(prod, p[i].second));
        prod = mul(prod, p[i].first / p[i].second);
    }

    for (int i = res.size() - 1; i >= 0; i--)
        cout << res[i];
    cout << endl;

    return 0;
}

时间复杂度 O ( n log ⁡ n + k ) O(n\log n+k) O(nlogn+k) k k k是高精度需要的时间,最差情况下可能达到 n 2 n^2 n2,空间 O ( n ) O(n) O(n)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/114381477