NC16561 国王的游戏

国王的游戏

https://ac.nowcoder.com/acm/problem/16561

思路:

首先我们清楚,交换任意两个相邻大臣的位置,对其他大臣获得的金币数不会造成影响。题目要求使得获得奖赏最多的大臣,所获奖赏尽可能的少,也就是让最大值尽可能小,并且国王固定在队伍的最前面,所以我们考虑后面的大臣即可。

在n(n≥2)个大臣中找出任意相邻的两个大臣A与B,记他们左右手的值分别为aLaRbLbR ,以及在A之前的所有大臣和国王左手上数字的乘积为pre

前乘积 A B
pre aLaR bLbR

假如此时A和B获得的金币数的最大值最小,则我们有不等式
不等式 ,   即A、B获得的金币数的最大值小于等于交换位置后B、A获得的金币数的最大值

很显然:
图片说明
图片说明
结合上面的不等式,我们可以推断出:
图片说明
化简得到:图片说明

所以,我们只需要对大臣们进行排序,让他们满足上面化简得到的不等式,
排序完了以后再从第一个大臣开始遍历,找到最多需要多少个金币即可

代码

*对于 100%的数据,有 1 ≤ n ≤1,000,0 < a,b < 10000。数据过大,这里无耻的复制了别人的大数计算的代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef struct people {
    int leftHand;   //左手上的数
    int rightHand;  //右手上的数
} people;

//需要用到大数计算

//一个大数乘一个int数
//返回num1 * num2
vector<int> multiply(const vector<int> &num1, int num2) {
    int carry = 0;    //记录进位
    vector<int> ans;    //记录答案
    for (int i = 0; i < num1.size() || carry != 0; ++i) {
        //如果还在num1的范围内,和num1相乘一位
        if (i < num1.size()) {
            carry += num1[i] * num2;
        }
        ans.push_back(carry % 10);
        carry /= 10;
    }
    return ans;
}

//一个大数除一个int
//返回 num1 / num2
vector<int> divide(const vector<int> &num1, int num2) {
    int temp = 0; //工具人变量,用来做除法
    vector<int> ans;    //记录答案
    //倒着循环,因为大数是倒着记的
    for (int i = num1.size() - 1; i >= 0; --i) {
        temp = temp * 10 + num1[i];
        ans.push_back(temp / num2);
        temp %= num2;
    }
    //因为大数是倒着记的,所以输出的答案也要倒过来,顺便把前面多出来的0删掉
    reverse(ans.begin(), ans.end());
    while (ans.back() == 0 && ans.size() > 1) {
        ans.pop_back();
    }
    return ans;
}

//判断num1是否大于num2
bool operator>(const vector<int> &num1, const vector<int> &num2) {
    //如果num1和num2位数不同,位数多的数更大
    if (num1.size() != num2.size()) {
        return num1.size() > num2.size();
    }
    for (int i = num1.size() - 1; i >= 0; --i) {
        if (num1[i] != num2[i]) {
            return num1[i] > num2[i];
        }
    }
    return false;
}

//输出大数
ostream &operator<<(ostream &output, vector<int> &num) {
    for (int i = num.size() - 1; i >= 0; --i) {
        output << num[i];
    }
    return output;
}

int main() {
    int temp;   //工具人变量
    int n;  //总人数(国王+大臣)
    cin >> n;
    n++;
    people pps[n];  //pps[0]为国王,其他为大臣
    for (int i = 0; i < n; ++i) {
        cin >> temp;
        pps[i].leftHand = temp;
        cin >> temp;
        pps[i].rightHand = temp;
    }
    //对大臣进行排序,让最大的金币数最少
    for (int i = 1; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            if (pps[i].leftHand * pps[i].rightHand > pps[j].leftHand * pps[j].rightHand) {
                swap(pps[i], pps[j]);
            }
        }
    }
    vector<int> coins, maxCoins; //金币数和最大金币数
    coins.push_back(pps[0].leftHand);
    for (int i = 1; i < n; ++i) {
        vector<int> tempCoins = divide(coins, pps[i].rightHand);  //第i个大臣的金币数
        if (tempCoins > maxCoins || maxCoins.empty())maxCoins = tempCoins;
        coins = multiply(coins, pps[i].leftHand);
    }
    cout << maxCoins;
}
全部评论

相关推荐

HR_丸山彩同学:你的项目描述里,系统设计讲了很多:MemCube是什么、三级存储架构怎么设计、四种遗忘策略分别是什么。这些面试的时候讲没问题,但简历上不需要这么细。 简历要突出的是影响力,不是实现细节。面试官看简历的时候想知道的是「这个项目有多大价值」,不是「这个项目具体怎么实现的」。实现细节是面试时候聊的 怎么改:技术细节可以精简为一句「采用三级存储架构+四种遗忘策略」,把省出来的篇幅用来写影响力。比如:项目有没有开源?有没有写成技术博客?有没有被别人使用过? 校园经历没有任何信息量,任何人都可以写这句话,写了等于没写。更关键的是,你投的是技术岗,校园活动经历本来就不是加分项。如果非要写,必须写出具体的数字和成果。如果你没有这些数字,那就老老实实删掉 「端到端耗时缩减30-40%」要给出确切数字和绝对值。从1000ms降到600ms是降了40%,从100ms降到60ms也是降了40%,但这两个含义完全不一样。其他也是,涉及到数据,准备好证据,口径统一,面试会问 「熟练」「熟悉」「了解」混在一起用,读起来很乱。而且「了解前端需求」最好改成「具备前后端协作经验」
点赞 评论 收藏
分享
2025-12-28 22:19
门头沟学院 Java
不敢追165女神:简历写得毫无特点,你说你要是大二或者大三找寒假实习到暑期实习这段时间,你的简历还能约到面试。但是你是研究生哥,面试官不会因为你是研究生而降低要求,反而会觉得你是研究生才学了这么一点?为什么我不找个同阶段的本科生?
简历中的项目经历要怎么写
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务