AcWing 114.国王游戏

题目传送门Luogu

题目传送门AcWing

一、公式推导

我们对于国王身后的两个点来分析

队列可能是这样的:

左手 右手
国王 a0 b0
p1 a1 b1
p2 a2 b2

根据题意:每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

那么我们计算可得当前情况下大臣的最大金币数量: ans1=max(a0b1,a0a1b2)

队列也有可能是这样的

左手 右手
国王 a0 b0
p2 a2 b2
p1 a1 b1

那么我们计算可得 ans2=max(a0b2,a0a2b1)

我们来对比一下两个答案:
ans1=max(a0b1,a0a1b2)

ans2=max(a0b2,a0a2b1)


k1=a0b1
k2=a0a1b2
k3=a0b2
k4=a0a2b1

因为a0a1>a0,所以 a0a1b2>a0b2,即 k2>k3

因为a0a2>a0,所以 a0a2b1>a0b1,即 k4>k1

如果想要 ans1<ans2,那么 max(k1,k2)<max(k3,k4),因为上面已经知道k2>k3, 所以 k4>k2

即: a0a2b1>a0a1b2

不等式变型

a0a2b2>a0a1b1

消去a0

a2b2>a1b1

也就是:
a1b1<a2b2

也就是说,当 a1b1<a2b2时,可以得到 ans1<ans2,也就是为了使ans更小,需要将aibi较小的放在前面,我们以aibi为关键字排序即可。

同时,由于数据范围是:
n=1000,同时 a<=10000,连乘就是 100010000相乘,需要用到高精度。

二、简单版本代码

#include <bits/stdc++.h>

using namespace std;
const int N = 10010;
typedef long long LL;
struct Person {
    int left, right;
} person[N];
int n;

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

int main() {
    cin >> n;
    //输入
    for (int i = 0; i <= n; i++)
        cin >> person[i].left >> person[i].right;
    //排序,注意国王不参加排序
    sort(person + 1, person + 1 + n, cmp);

    LL lcj = 1;//连乘积
    LL res = 0;
    for (int i = 0; i <= n; i++) {
        //猴子选大王
        res = max(res, lcj / person[i].right);
        //更新连乘各
        lcj *= person[i].left;
    }
    printf("%d", res);
    return 0;
}

三、高精度版本代码

#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;
    for (int i = a.size() - 1; i >= 0; i--) {
        if (a[i] > b[i]) return a;
        if (a[i] < b[i]) return b;
    }
    return a;
}

int main() {
    //优化输入
    ios::sync_with_stdio(false);
    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> lcj;
    lcj.push_back(person[0].left);

    //结果
    vector<int> res;
    res.push_back(0);//在做高精度时,也需要进行一步初始化

    for (int i = 1; i <= n; i++) {
        int r;//余数,本题中因为只需要下取整,所以余数无意义
        res = max_vec(res, div(lcj, person[i].right, r));
        lcj = mul(lcj, person[i].left);
    }
    //倒序输出高精度数组中的值
    for (int i = res.size() - 1; i >= 0; i--)
        printf("%d", res[i]);
    return 0;
}

posted @   糖豆爸爸  阅读(393)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2018-07-21 在Centos中安装aria2c
2016-07-21 PHP、JAVA、C#、Object-C 通用的DES加密
Live2D
点击右上角即可分享
微信分享提示