题解
【入门】开学大采购
1 条题解
-
0
解题思路
这道题要我们把 n 元经费全部花完,买篮球和排球。
先看看题目给了我们哪些条件:
- 篮球和排球都至少买 1 个;
- 经费要全部用完,一分钱都不能剩;
- 买的总数要超过 50 个(注意是"超过",也就是大于 50,正好 50 个也不行);
- 输出的时候篮球从少到多排。
怎么把所有可行的方案都找出来呢?我们可以用"枚举"的办法:把篮球的个数 a 一个个试过去。
篮球是 x 元一个,买了 a 个篮球,就花掉了 ax 元。剩下的钱就是 rest = n - ax,全部用来买排球。
排球是 y 元一个。如果 rest 能被 y 整除,说明钱能正好花完,排球个数就是 b = rest / y;如果不能整除,就说明钱花不完,这个方案不行。
那么篮球个数 a 从几开始试呢?题目说篮球至少买 1 个,所以从 a = 1 开始。篮球越买越多,最多买到 a*x <= n,也就是经费只够买篮球这么多。
每试一个 a,我们要检查两个条件:
- b >= 1(排球至少买 1 个);
- a + b > 50(总数要超过 50 个)。
两个条件都满足,就输出这一组方案。
为什么输出顺序天然正确?因为我们从 a = 1、2、3……从小到大枚举篮球个数,先试到的 a 小、先输出,所以篮球自然是从少到多;每一行先打印 a 再打印 b,正好就是题目要求的顺序。
我们用样例来走一遍:n = 1000,x = 25,y = 15。
- a = 1:买 1 个篮球花 25 元,剩 1000 - 25 = 975 元,975 / 15 = 65,排球 65 个,总数 1 + 65 = 66 > 50,输出 1 65;
- a = 4:买 4 个篮球花 100 元,剩 900 元,900 / 15 = 60,总数 4 + 60 = 64 > 50,输出 4 60;
- a = 7:买 7 个篮球花 175 元,剩 825 元,825 / 15 = 55,总数 7 + 55 = 62 > 50,输出 7 55;
- a = 10:买 10 个篮球花 250 元,剩 750 元,750 / 15 = 50,总数 10 + 50 = 60 > 50,输出 10 50;
- a = 13:买 13 个篮球花 325 元,剩 675 元,675 / 15 = 45,总数 13 + 45 = 58 > 50,输出 13 45;
- a = 16:买 16 个篮球花 400 元,剩 600 元,600 / 15 = 40,总数 16 + 40 = 56 > 50,输出 16 40;
- a = 19:买 19 个篮球花 475 元,剩 525 元,525 / 15 = 35,总数 19 + 35 = 54 > 50,输出 19 35;
- a = 22:买 22 个篮球花 550 元,剩 450 元,450 / 15 = 30,总数 22 + 30 = 52 > 50,输出 22 30;
- a = 25:买 25 个篮球花 625 元,剩 375 元,375 / 15 = 25,总数 25 + 25 = 50,正好 50 个——题目要"超过 50",50 不大于 50,所以不能输出!
和样例完全一致,我们这样做是对的。
那 a = 2、a = 3 这些为什么没有输出呢?以 a = 2 为例:剩 1000 - 50 = 950 元,950 / 15 除不尽(有余数),钱不能正好花完,不满足"经费全部用完",直接跳过。也就是说,只要 rest % y != 0,这个 a 就跳过。
参考代码
// P372 【入门】开学大采购 // 思路:枚举篮球个数 a,用公式算排球个数 b,判断所有条件是否满足 #include <iostream> using namespace std; int main() { // n 是学校经费,x 是篮球单价,y 是排球单价 int n, x, y; cin >> n >> x >> y; // 枚举篮球个数 a,从 1 开始,篮球至少要买 1 个 // a 最大到 n/x(经费只买篮球最多能买几个) for (int a = 1; a * x <= n; a++) { // 买完 a 个篮球后,剩下 rest 元用来买排球 int rest = n - a * x; // 剩下的钱要刚好能买整数个排球(能整除 y) if (rest % y != 0) { continue; // 不能整除,说明钱不能正好花完,跳过 } // 排球个数 b int b = rest / y; // 条件检查: // 1. 排球至少买 1 个:b >= 1 // 2. 总数要超过 50 个:a + b > 50(注意是"超过",不含 50) if (b >= 1 && a + b > 50) { // 篮球个数从小到大枚举,输出顺序自然正确 cout << a << " " << b << endl; } } return 0; }复杂度分析
- 时间复杂度:篮球个数 a 从 1 试到 n/x,一共约 n/x 次,每次循环内部都是常数次运算,所以是 O(n/x)。题目的数据范围里 n 不大,完全够快。
- 空间复杂度:只用到了几个整型变量,是 O(1)。
- 1