题解:学而思编程 汽水兑奖

【题目来源】

学而思编程:汽水兑奖

【题目描述】

汽水公司的免费兑换规则如下:

收集 \(b\) 个瓶盖,可以免费换一瓶新的汽水。

收集 \(c\) 个空瓶子,也可以换一瓶新的汽水。

小X一开始有尚未开封的汽水 \(a\) 瓶,请问利用上述规则,最终可以喝到多少瓶汽水?注意不可以向他人借瓶盖或瓶子。

【输入】

一行三个整数 \(a,b, c\),其含义同题目描述。

【输出】

一行一个整数,表示最多可以喝到多少瓶汽水。

【输入样例】

10 5 4

【输出样例】

17

【核心思想】

  1. 问题分析:初始有 \(a\) 瓶未开封汽水,每喝一瓶产生 \(1\) 个瓶盖和 \(1\) 个空瓶。收集 \(b\) 个瓶盖或 \(c\) 个空瓶可换 \(1\) 瓶新汽水。求最终能喝到的汽水总数。这是一个模拟兑换 + 余数累加问题,关键在于同时追踪瓶盖和空瓶的累计数量,并计算每次能兑换的新汽水。

  2. 算法选择

    • 循环模拟:每轮喝掉当前所有汽水,累加瓶盖和空瓶,计算可兑换的新汽水
    • 余数复用:用 s1 % bs2 % c 保留不足以兑换的余数,与新产生的合并
  3. 关键步骤

    • 初始化:读取 \(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
  4. 时间/空间复杂度

    • 时间复杂度:\(O(\log_{min(b,c)} a)\),每轮至少将剩余量除以 \(min(b,c)\),收敛快
    • 空间复杂度:\(O(1)\),仅需常数变量
  5. 余数累加的核心思想

    • 双资源追踪:瓶盖和空瓶是两种独立的兑换资源,需分别累计和兑换
    • 余数复用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
posted @ 2026-07-05 16:00  团爸讲算法  阅读(6)  评论(0)    收藏  举报