分糖果
1 条题解
-
0
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