这道题可以使用分治算法和暴力枚举来解决
先写一下分治的思路
我们需要找到一个k使得k%n的值在L和R区间内最大。
递归步骤:
要先知道:
如果 L > R,说明区间为空,返回 0。
步骤:
计算中间值 mid。
如果 mid % n 不为 0,则比较 mid % n 和右半边 [mid + 1, R] 的结果,返回较大的值。
如果 mid % n 为 0,则递归地在左半边区间 [L, mid - 1] 查找。
举个栗子
假设 L = 3, R = 10, n = 5
第一次调用 find(3, 10, 5):
mid = 6
mid % n = 6 % 5 = 1(非零)
比较 1 和 find(7, 10, 5) 的结果。
第二次调用 find7, 10, 5):
mid = 8
mid % n = 8 % 5 = 3(非零)
比较 3 和 find(9, 10, 5) 的结果。
第三次调用 find(9, 10, 5):
mid = 9
mid % n = 9 % 5 = 4(非零)
返回 4。
第二次调用返回 3 和 4 比较,返回 4。
第一次调用返回 1 和 4 比较,返回 4。
最终答案为 4。
OK,写个栗子(第一次发题解,用ai再给我改了一遍)
// 计算按照规则分糖果后剩余的数量
int jisuan(int n, int k) {
int shengYu = k;
while (shengYu >= n) {
shengYu -= n;
}
return shengYu;
}
// 分治算法函数
int fenZhiSuanFa(int n, int zuoBian, int youBian) {
if (zuoBian == youBian) {
return jisuan(n, zuoBian);
}
int zhongJian = (zuoBian + youBian)/2;
int shengYu_zhongJian = jisuan(n, zhongJian);
int shengYu_zhongJian_jia_1 = jisuan(n, zhongJian + 1);
int shengYu_zhongJian_jian_1 = jisuan(n, zhongJian - 1);
if (shengYu_zhongJian >= shengYu_zhongJian_jian_1 && shengYu_zhongJian >= shengYu_zhongJian_jia_1) {
return shengYu_zhongJian;
} else if (shengYu_zhongJian_jian_1 > shengYu_zhongJian) {
return fenZhiSuanFa(n, zuoBian, zhongJian - 1);
} else {
return fenZhiSuanFa(n, zhongJian + 1, youBian);
}
}
其余种算法
暴力枚举
其中可以做一些优化
1.当枚举到一个数等于小朋友数-1时,跳出循环直接输出
2.处理所有模数为 0 的情况:
如果所有可能的 k 值模 n 都为 0,并且 L 允许我们拿更少的糖果,输出 n - 1。
贪心
想象一下我们有很多堆糖果,每堆有n个(n是小朋友的数量)。我们先看看最多能有多少整堆的糖果,之后就是用R(最多能拿的糖果数)除以n。比如说R是 17,n是 5,那 17 除以 5 等于 3 堆还余 2 个,这里的 3 就是商,2 就是余数。然后我们想啊,如果我们能拿的最少糖果数L,比 3 堆糖果(也就是n乘以 3)再多 2 个(余数)这个数量要小或者相等,那我们就拿这个数量(3 堆再多 2 个)的糖果。按照分糖果的规则,所有小朋友每次拿一个,最后剩下的就是那 2 个,这就是我们能得到的最多剩余糖果了。但是,如果L比这个 3 堆再多 2 个的数量要大呢?那就说明在L到R这个范围里,最划算的就是拿L个糖果了。然后按照分糖果规则分完后,剩下的糖果数量就是L除以n得到的余数。就好像L是 13,n是 5,13 除以 5 余 3,那最后剩下的就是 3 个糖果。
(第一次发题解,发的不行,建议大家就是做个参考,内容用ai验证过了)
其实就是看同学都发了必须对标以下(bushi)
//是谁说直接模拟会爆的