题解:学而思编程 汽水兑奖
【题目来源】
学而思编程:汽水兑奖
【题目描述】
汽水公司的免费兑换规则如下:
收集 \(b\) 个瓶盖,可以免费换一瓶新的汽水。
收集 \(c\) 个空瓶子,也可以换一瓶新的汽水。
小X一开始有尚未开封的汽水 \(a\) 瓶,请问利用上述规则,最终可以喝到多少瓶汽水?注意不可以向他人借瓶盖或瓶子。
【输入】
一行三个整数 \(a,b, c\),其含义同题目描述。
【输出】
一行一个整数,表示最多可以喝到多少瓶汽水。
【输入样例】
10 5 4
【输出样例】
17
【核心思想】
-
问题分析:初始有 \(a\) 瓶未开封汽水,每喝一瓶产生 \(1\) 个瓶盖和 \(1\) 个空瓶。收集 \(b\) 个瓶盖或 \(c\) 个空瓶可换 \(1\) 瓶新汽水。求最终能喝到的汽水总数。这是一个模拟兑换 + 余数累加问题,关键在于同时追踪瓶盖和空瓶的累计数量,并计算每次能兑换的新汽水。
-
算法选择:
- 循环模拟:每轮喝掉当前所有汽水,累加瓶盖和空瓶,计算可兑换的新汽水
- 余数复用:用
s1 % b和s2 % c保留不足以兑换的余数,与新产生的合并
-
关键步骤:
- 初始化:读取 \(a\)(初始汽水)、\(b\)(瓶盖兑换数)、\(c\)(空瓶兑换数)
s = 0:累计喝到的汽水总数s1 = 0:累计瓶盖数(模 \(b\) 意义下)s2 = 0:累计空瓶数(模 \(c\) 意义下)- 循环兑换(当
a != 0时):s += a:喝掉当前 \(a\) 瓶汽水s1 = s1 % b + a:更新瓶盖总数 = 上轮余数 + 本轮新产生 \(a\) 个s2 = s2 % c + a:更新空瓶总数 = 上轮余数 + 本轮新产生 \(a\) 个a = s1 / b + s2 / c:本轮可兑换的新汽水数 = 瓶盖兑换数 + 空瓶兑换数
- 输出
s
-
时间/空间复杂度:
- 时间复杂度:\(O(\log_{min(b,c)} a)\),每轮至少将剩余量除以 \(min(b,c)\),收敛快
- 空间复杂度:\(O(1)\),仅需常数变量
-
余数累加的核心思想:
- 双资源追踪:瓶盖和空瓶是两种独立的兑换资源,需分别累计和兑换
- 余数复用:
s1 % b保留不够兑换的瓶盖,与新喝的汽水产生的瓶盖合并,避免资源浪费 - 同步更新:每轮喝掉的汽水同时产生等量的瓶盖和空瓶,两种资源同步增长
- 收敛性:每轮兑换后
a减少(或增长缓慢),最终必然收敛到 \(0\) - 适用于"多资源兑换 + 循环模拟"类问题,余数累加确保资源不浪费,模拟直至无法继续兑换
【算法标签】
数学
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int a, b, c, s, s1, s2; // a: 初始a, b: 除数1, c: 除数2, s: 总和, s1,s2: 余数累加
int main()
{
cin >> a >> b >> c; // 输入a,b,c
while (a != 0) // 当a不为0时循环
{
s += a; // 累加a到总和s
s1 = s1 % b + a; // 更新s1的余数累加
s2 = s2 % c + a; // 更新s2的余数累加
a = s1 / b + s2 / c; // 计算新的a值
}
cout << s; // 输出总和
return 0;
}
【运行结果】
10 5 4
17
浙公网安备 33010602011771号