top1编程
← 返回题目
题解

分糖果

1 条题解

  • 0
    @ 2026-8-6 0:09:19

    P4700 分糖果(基础)

    解题思路

    想象你有一大把糖果要分给 n 个小朋友。大家围成一圈,只要篮子里还有不少于 n 颗糖,就每个人拿一颗,拿完一轮篮子里就少了 n 颗。这样一轮一轮拿下去,直到剩下的糖不足 n 颗,剩下的就全归你当奖励。下面分三步推导出答案。

    **第一步,转成数学问题。**如果你拿了 k 颗糖,每轮拿走 n 颗,最后剩下的就是 k 除以 n 的余数。比如 n=7,拿了 20 颗,20 ÷ 7 = 2 轮还余 6,奖励就是 6 颗。所以问题变成:在 L 到 R 之间选一个数 k,让 k % n 最大。

    **第二步,想清楚最大值。**余数最大是 n-1。能拿到余数 n-1 的数,一定是 n 的倍数减 1,比如 n=7 时是 6、13、20、27……。

    **第三步,判断 n-1 能不能取到。**先把 k 取成 R,算出 R%n。再看比 R 稍小一点、余数正好是 n-1 的那个数 R - (R%n) - 1 还在不在 [L,R] 里:如果 R - (R%n) - 1 ≥ L,就说明能取到 n-1,答案就是 n-1;否则答案只能是 R%n。

    为什么从 R 往小想?对同一个 n 来说,k 越大,余数一般越大,最优答案要么就是 R 的余数,要么是极限的 n-1,中间的值不会比这两者更好。所以只要判断一下 n-1 能不能取到,就省去了逐个枚举 k 的麻烦,这也是"数学推导"代替"暴力枚举"的典型例子。

    举个具体例子:n=7,L=16,R=23。R%7=2,R-2-1=20 ≥ 16,所以取 k=20,20%7=6,奖励 6 颗,这就是最大奖励。再比如 n=5,L=5,R=5,只能拿 5 颗,5%5=0,奖励是 0,千万别错输成 4。

    参考代码

    // 分糖果:CSP-J2021 T1,n人分k块糖,余下的归自己,求最多奖励
    #include <iostream>
    using namespace std;
    
    int main() {
        long long n, L, R;
        cin >> n >> L >> R;
        // 奖励 = k % n,在 [L,R] 中找一个 k 使 k%n 最大
        // 先取 k=R 得余数 answer;若 R-answer-1 还在 [L,R] 内,
        // 说明能取到余数 n-1(最优),否则答案就是 answer
        long long answer = R % n;
        if (R - answer - 1 >= L) answer = n - 1;
        cout << answer << endl;
        return 0;
    }
    

    复杂度分析

    只做了几次加减法和比较,时间复杂度 O(1),空间 O(1)。无论 L、R 多大(最大可到 10^9),都能瞬间算出来,所以要用 long long 存,防止中间结果越界。

    • 1