1 条题解
-
0
题目 B. ICPC Square 详细题解
问题重述
有 层楼(编号 到 ),电梯规则:从 层可以到 层当且仅当
- 是 的倍数,且
- 。
初始在 层,可以乘坐零次或多次电梯,问能到达的最高楼层(不超过 )。
关键观察
-
可达楼层必为 的倍数
因为从 出发,每次跳到的都是当前楼层的倍数,所以所有可达楼层都是 的倍数。 -
归一化
$$N' = \left\lfloor \frac{N}{S} \right\rfloor,\quad D' = \left\lfloor \frac{D}{S} \right\rfloor $$
将问题除以 :令起始楼层变为 ,目标是在 内从 出发,每次可以跳到当前数 的倍数 且 。
最终答案乘以 即可。
可达上界分析
设当前在 ,下一次跳到 ( 整数)。则增量
因此 ,即 。
结论:任何非自身的倍数跳跃,其起点必须 。
若想跳到较大的数 ,它必须有一个真因子 ()满足 且 。
由于 ,且 的最小真因子最大为 (当 为偶数时),所以因此 ,即 。
另外显然 。故能到达的楼层 不可能超过
能否到达 的判断
令 。若 (即 且 ?实际上 因为 ),则起始楼层 就是答案。下文假设 。
情况 1: 是偶数
取 ,则
- 是整数且 (因为 ),
- 从 可以直接跳到 : 是 的倍数且 成立(因 ),
- 从 可以跳到 : 是 的倍数且 。
因此 可达。
情况 2: 是奇数
需要寻找一个真因子 满足:
- ,
- 是 的倍数,
- 。
由于 是奇数,其最小真因子 可能大于 ?实际上奇数的最小真因子最大为 (例如 的因子 )。但更通用的方法是枚举 的所有因子 (),检查是否 且 。
因为 ,所以 等价于 。因此需要存在一个真因子 满足且 。
枚举 的所有因子可在 时间内完成。若找到这样的 ,则 可达(从 跳到 ,再跳到 )。若找不到,则 不可达。
不可达时的次优解
若 不可达,则 一定是偶数(因为 是奇数),且 ,故根据情况 1, 可达。因此答案为 。
算法步骤
- 读取 。
- 计算 ,。
- 若 ,则只能停留在 ,答案为 。否则:
- 。
- 如果 是偶数,则 。
- 否则( 奇数),枚举 的所有因子 (),检查是否存在真因子 满足 且 。
- 若存在,则 ;
- 否则 。
- 输出 。
复杂度分析
- 归一化 。
- 枚举因子 ,因为 。
- 总时间复杂度 ,可轻松通过 。
边界情况处理
- 当 时,,直接输出 (只能停留在起点)。
- 当 时,,,此时 可达(起点本身),答案为 ,正确。
- 当 时(奇数),因子只有 ,检查 是否在 内,即 。由于 , 满足,故 可达,答案正确。
参考代码(C++)
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { ll N, D, S; cin >> N >> D >> S; ll Np = N / S; ll Dp = D / S; if (Dp == 0) { cout << S << endl; return 0; } ll Y = min(2 * Dp, Np); if (Y % 2 == 0) { cout << Y * S << endl; return 0; } // Y is odd, check if reachable bool ok = false; for (ll x = 1; x * x <= Y; ++x) { if (Y % x == 0) { ll f1 = x, f2 = Y / x; if (f1 != Y && f1 >= Y - Dp && f1 <= Dp) ok = true; if (f2 != Y && f2 >= Y - Dp && f2 <= Dp) ok = true; } } if (ok) cout << Y * S << endl; else cout << (Y - 1) * S << endl; return 0; }
- 1
信息
- ID
- 7153
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者