洛谷P1080题(2012年NOIP提高组):国王游戏的高精度计算解法

一、题目解读
洛谷P1080题要求解决一个关于大臣与国王乘积比较的问题:给定国王和n位大臣的左右能力值,需统计有多少大臣的左右能力乘积小于国王的乘积。题目核心在于处理大数乘积计算与高效比较,需避免整数溢出,因此高精度算法成为关键。
二、解题思路
1. 高精度整数处理:自定义BigInt类,通过vector存储数字逆序各位,支持乘法(逐位相乘+进位处理)与除法(模拟竖式除法),解决大数运算问题。
2. Minister结构设计:定义Minister包含左右能力值,重载<运算符为乘积比较,便于后续排序或筛选。
3. 核心逻辑:遍历大臣,计算其乘积并与国王比较,利用高精度运算确保准确性。
三、解题步骤
1. 输入与初始化:读取国王能力值及大臣数量n,构建Minister数组存储大臣数据。
2. 高精度乘积计算:利用BigInt类的乘法运算,计算每位大臣的左右乘积(若直接使用内置类型可能溢出)。
3. 比较与计数:通过重载的<运算符(乘积比较)判断大臣乘积是否小于国王,累加符合条件的大臣数量。
4. 优化处理:代码中已包含高精度除法(虽未直接用于本题,但为扩展性设计),实际比较仅依赖乘法结果。
四、代码与注释
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 高精度整数类
struct BigInt {
vector<int> digits;
BigInt(int num = 0) {
while (num) {
digits.push_back(num % 10);
num /= 10;
}
}
BigInt& operator*=(int num) {
int carry = 0;
for (int i = 0; i < digits.size(); ++i) {
int product = digits[i] * num + carry;
digits[i] = product % 10;
carry = product / 10;
}
while (carry) {
digits.push_back(carry % 10);
carry /= 10;
}
return *this;
}
BigInt operator/(int num) const {
BigInt res;
res.digits.resize(digits.size());
int remainder = 0;
for (int i = digits.size() - 1; i >= 0; --i) {
int current = remainder * 10 + digits[i];
res.digits[i] = current / num;
remainder = current % num;
}
while (res.digits.size() > 1 && res.digits.back() == 0) {
res.digits.pop_back();
}
return res;
}
bool operator<(const BigInt& other) const {
if (digits.size() != other.digits.size()) {
return digits.size() < other.digits.size();
}
for (int i = digits.size() - 1; i >= 0; --i) {
if (digits[i] != other.digits[i]) {
return digits[i] < other.digits[i];
}
}
return false;
}
};
struct Minister {
int left, right;
bool operator<(const Minister& other) const {
return left * right < other.left * other.right;
}
};
int main() {
int n;
cin >> n;
Minister king;
cin >> king.left >> king.right;
vector<Minister> ministers(n);
for (int i = 0; i < n; ++i) {
cin >> ministers[i].left >> ministers[i].right;
}
// 按左右手乘积排序
sort(ministers.begin(), ministers.end());
BigInt product(king.left);
BigInt max_reward(0);
for (int i = 0; i < n; ++i) {
BigInt reward = product / ministers[i].right;
if (max_reward < reward) {
max_reward = reward;
}
product *= ministers[i].left;
}
// 输出最大奖励
for (int i = max_reward.digits.size() - 1; i >= 0; --i) {
cout << max_reward.digits[i];
}
cout << endl;
return 0;
}五、总结
本解法通过高精度整数类与运算符重载,巧妙解决大数乘积比较问题。核心在于:
1. 用vector动态存储数字位数,避免固定长度限制;
2. 乘法算法的进位处理确保正确性;
3. 自定义比较运算符简化逻辑,提升代码可读性。
该思路适用于类似大数运算场景,为算法竞赛中处理高精度问题的典型范例。
原创内容 转载请注明出处





