1 条题解
-
0
题意简述
有 个征兆,第 个征兆每 年发生一次(即在 年)。
征兆必须按顺序依次发生:- 先等第 个征兆发生,设发生年份为 。
- 然后从 年开始等第 个征兆,它必须是 的倍数且严格大于 。
- 依此类推。
求第 个征兆发生的年份。
算法思路
设 表示当前已经发生的最后一个征兆的年份。
初始时没有征兆发生,可以认为 (实际上第一个征兆会直接取 ,下面会解释)。
对于第 个征兆(周期为 ),我们需要找到最小的 使得:
即:
$$k = \left\lfloor \frac{cur}{a_i} \right\rfloor + 1 $$那么该征兆发生的年份为:
$$k \cdot a_i = \left( \left\lfloor \frac{cur}{a_i} \right\rfloor + 1 \right) \cdot a_i $$
标程中的简洁写法
标程使用了一行核心代码:
cur += e - cur % e;我们推导一下为什么这样写等价于上面的计算。
设 , 是上一个征兆的年份。
- 是 除以 的余数。
- 如果 ,那么:
要找到大于 的最小的 的倍数,就是:
所以增加的年份为:
因此新的 为:
特殊情况验证
- 若 已经是 的倍数(),则新年份为 ,严格大于 ,正确。
- 初始时 ,,则第一个征兆年份为 ,正确。
时间复杂度
每个测试用例 ,总复杂度 ,完全可行。
完整代码(已给出)
#include <iostream> #include <vector> using namespace std; void solve() { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } long long cur = 0; for (int e : a) { cur += e - cur % e; } cout << cur << endl; } int main() { int t; cin >> t; for (int i = 1; i <= t; i++) { solve(); } return 0; }
举例验证
输入:
1 6 3 2 4 5 9 18执行过程:
步骤 (更新前) (更新后) 1 3 0 3 2 3 1 4 3 4 0 4 8 4 5 8 3 2 10 5 9 10 1 8 18 6 18 0 18 36 输出:,与题目示例一致。
总结
这道题的核心是贪心地依次计算每个征兆的最早发生年份,利用取模运算快速跳转到下一个倍数。
公式:是解决此类“依次寻找严格大于当前值的最小倍数”问题的常用技巧。
- 1
信息
- ID
- 6429
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者