题解:洛谷 P14974 Chip Exchange

【题目来源】

洛谷:P14974 [USACO26JAN1] Chip Exchange B - 洛谷

【题目描述】

奶牛 Bessie 拥有 \(A\) 个 A 型芯片和 \(B\) 个 B 型芯片(\(0\le A,B\le 10^9\))。她可以按意愿多次执行以下操作:

  • 如果你至少有 \(c_B\) 个 B 型芯片,则可以用 \(c_B\) 个 B 型芯片交换 \(c_A\) 个 A 型芯片(\(1\le c_A,c_B\le 10^9\))。

请你确定一个最小的非负整数 \(x\),使得以下条件成立:在收到 \(x\) 个额外的随机芯片后,可以保证 Bessie 最终能够拥有至少 \(f_A\) 个 A 型芯片(\(0\le f_A\le 10^9\))。

【输入】

第一行包含 \(T\),表示独立测试用例的数量(\(1\le T\le 10^4\))。

接下来是 \(T\) 个测试用例,每个用例由五个整数 \(A\)\(B\)\(c_A\)\(c_B\)\(f_A\) 组成。

【输出】

每个测试用例的答案输出在单独的一行。

注意:本题涉及的大整数可能需要使用 64 位整数数据类型(例如,C/C++ 中的 "long long")。

【输入样例】

2
2 3 1 1 6
2 3 1 1 4

【输出样例】

1
0

【核心思想】

  1. 问题分析:给定 \(A\) 个 A 芯片、\(B\) 个 B 芯片,可用 \(c_B\) 个 B 换 \(c_A\) 个 A。求最小非负整数 \(x\),使得收到 \(x\) 个额外随机芯片后,能保证最终拥有至少 \(f_A\) 个 A 芯片。这是一个数学分析 + 分类讨论问题,关键在于分析转换效率 \(c_A\)\(c_B\) 的关系,以及最坏情况下额外芯片的分配。

  2. 算法选择

    • 数学推导:先尽可能用现有 B 换 A,然后根据 \(c_A\)\(c_B\) 的大小关系分类讨论
    • 最坏情况假设:额外 \(x\) 个芯片都是最坏分配(即最不利于达成目标的分配),需要保证即使最坏也能达成
  3. 关键步骤

    • 初始转换a += b / cb * cab %= cb(先用尽现有 B)
    • 已达目标:若 a >= fa,输出 \(0\)
    • 转换效率高(\(c_A \geq c_B\)
      • 最坏情况:额外芯片全是 B(因为 B 可以换 A,且效率高)
      • 需要补足 A 缺口 fa - a,同时需要 cb - b 个 B 完成一次转换
      • numa = fa - a - 1(需要补足的 A,减1是因为可以借位)
      • numb = cb - b(完成一次转换需要的 B)
      • 答案 = numa + numb
    • 转换效率低(\(c_A < c_B\)
      • 最坏情况:额外芯片全是 A 或混合,需要精确计算
      • numa = (fa - a - 1) % ca(无法通过完整转换获得的 A 缺口)
      • numb = ceil((fa - a - numa) / ca) * cb - b(完成所需转换次数的 B 缺口)
      • 答案 = numa + numb
  4. 时间/空间复杂度

    • 时间复杂度:\(O(T)\),每个测试用例 \(O(1)\) 计算
    • 空间复杂度:\(O(1)\),常数变量
  5. 数学分类讨论的核心思想

    • 最坏情况保证:题目要求"保证"能达成目标,因此必须考虑额外 \(x\) 个芯片的最坏分配(全是对目标最不利的类型)
    • 转换效率决定策略
      • \(c_A \geq c_B\):B 换 A 划算,最坏情况是额外芯片全是 A(因为 A 不能直接换 B,但 B 可以换 A)。实际上最坏是缺少 B 来完成转换,因此需要补足 B 缺口和 A 缺口
      • \(c_A < c_B\):B 换 A 不划算,最坏情况是额外芯片全是 B(因为需要更多 B 才能换到足够 A)
    • 取模与上取整:精确计算转换次数和余数,避免浮点误差
    • 适用于"资源转换 + 最坏情况保证"的数学问题,核心在于分类讨论和精确计算

【解题思路】

【算法标签】

普及 #数学

【代码详解】

#include <bits/stdc++.h>
using namespace std;

#define int long long  // 将int定义为long long类型,避免大数溢出

int t, a, b, ca, cb, fa;  // t: 测试用例数量,a: 当前资源A数量,b: 当前资源B数量,ca: 每次转换获得的A数量,cb: 每次转换需要的B数量,fa: 目标A资源数量

signed main()  // 使用signed main()替代int main(),因为int被重定义为long long
{
    cin >> t;  // 读入测试用例数量

    while (t--)  // 处理每个测试用例
    {
        cin >> a >> b >> ca >> cb >> fa;  // 读入当前资源情况和目标

        int ans = 0;  // 初始化答案变量(未使用)

        // 先将现有的B资源尽可能转换为A资源
        // 计算可转换的次数:b / cb
        // 每次转换获得ca个A资源
        a += b / cb * ca;
        // 剩余不足一次转换的B资源
        b %= cb;

        // 如果转换后A资源已达到或超过目标
        if (a >= fa)
        {
            cout << 0 << endl;  // 无需额外操作
        }
        // 如果每次转换获得的A数量 >= 需要的B数量(转换效率高或相等)
        else if (ca >= cb)
        {
            // 需要额外获得的A资源数量
            int numa = fa - a - 1;
            // 需要额外获得的B资源数量(补足到下一次转换)
            int numb = cb - b;
            // 总成本为两者之和
            cout << numa + numb << endl;
        }
        // 如果每次转换获得的A数量 < 需要的B数量(转换效率低)
        else if (ca < cb)
        {
            // 需要额外获得的A资源数量(取模,表示无法通过完整转换获得的部分)
            int numa = (fa - a - 1) % ca;
            // 计算需要完整转换的次数,并转换为需要的B资源数量
            int numb = ceil(1.0 * (fa - a - numa) / ca) * cb - b;
            // 总成本为两者之和
            cout << numa + numb << endl;
        }
    }

    return 0;
}

【运行结果】

2
2 3 1 1 6
1
2 3 1 1 4
0
posted @ 2026-08-10 12:27  团爸讲算法  阅读(9)  评论(0)    收藏  举报