1 条题解
-
0
A. FizzBuzz 变种版 详细题解
题目理解
我们需要统计在 范围内,有多少个整数 满足:
关键观察:
- 总是满足条件,因为 ,。
- 对于一般的 ,我们要求两个余数相等。
数学推导
设 ,其中 (因为模 的余数只能是 )。
那么:
这意味着:
$$i - r \text{ 能被 } \mathrm{lcm}(3,5) = 15 \text{ 整除} $$所以:
对于 ,我们得到三个等差数列:
- :
- :
- :
结论
每 个连续整数中,恰好有 个满足条件(即 ,其中 )。
计数公式
设 ,(这里 是余数,注意与上面的 不同)。
完整周期部分:
从 到 ,有 个完整的长度为 的区间,每个区间贡献 个满足条件的数。
因此完整周期部分有 个数。剩余部分:
剩余部分是从 到 ,共 个数。
我们需要检查这些数中哪些满足条件。这些数是:
因为 ,所以:
- 对应 的情况,满足条件
- 对应 的情况,满足条件
- 对应 的情况,满足条件
- 对应 ,但 ,,不相等
- 以此类推...
实际上,我们只需要检查 是否满足 。
因为 且 。最终公式:
$$\text{ans} = 3 \times \left\lfloor \frac{n}{15} \right\rfloor + \text{count\_remainder}(n \bmod 15) $$其中 表示在 中满足 的个数。
剩余部分查找表
, 从 到 :
满足条件的 个数 0 1 1 0,1 2 2 0,1,2 3 3 4 5 6 7 8 9 10 11 12 13 14 观察发现,除了 时有特殊情况,当 时都是 个。
实际上更精确地说:- 如果 :剩余部分有 ,共 个
- 如果 :剩余部分有 ,共 个
- 如果 :剩余部分包含 ,共 个
但注意:当 时,剩余部分就是 ,正好 个。
所以:
更准确地说是 ?我们验证:
- : ✓
- : ✓
- : ✓
- : ✓
但注意 时,剩余数是 ,其中 满足, 不满足,共 个,公式成立。
简化公式
$$\text{ans} = 3 \times \left\lfloor \frac{n}{15} \right\rfloor + \min\left(n \bmod 15 + 1,\ 3\right) $$更简单的写法:
$$\text{ans} = 3 \times \left\lfloor \frac{n}{15} \right\rfloor + \min( (n \bmod 15) + 1,\ 3) $$等价地:
$$\text{ans} = 3 \times \left\lfloor \frac{n}{15} \right\rfloor + \min( n \bmod 15,\ 2) + 1 $$因为 。
标程验证
给定的 Python 代码:
t = int(input()) for i in range(t): n = int(input()) ans = 3 * (n // 15) n %= 15 for j in range(n + 1): if j % 3 == j % 5: ans += 1 print(ans)这个代码:
- 先计算完整周期数
- 然后对剩余部分 到 逐个判断,累加满足条件的个数
- 复杂度 ,完全可行
复杂度分析
- 每个测试用例 计算(若用公式)
- 总时间复杂度 ,可以轻松处理
最终公式代码实现(C++)
#include <iostream> using namespace std; int main() { int t; cin >> t; while (t--) { long long n; cin >> n; long long ans = 3 * (n / 15) + min(n % 15 + 1, 3LL); // 等价写法: ans = 3 * (n / 15) + min(n % 15, 2) + 1; cout << ans << endl; } return 0; }
验证示例
以 为例:
- ,完整周期贡献
- ,
- 总答案 ,匹配输出
以 为例:
- ,贡献
- ,
- 总答案 ,匹配输出
以 为例:
- ,贡献
- ,
- 总答案 ,匹配输出
总结
核心思想是发现 当且仅当 ,然后利用周期性快速计数,避免 的逐个判断。
- 1
信息
- ID
- 7208
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者