1 条题解
-
0
题目解析
给定区间 和目标最大公约数 ,需要找到两个数 和 (),使得 ,并且 尽可能大。如果有多个解,选择 最小的。
关键观察
1. 化简问题
如果 ,那么可以设 ,,其中 。
$$\left\lceil \frac{l}{G} \right\rceil \le a \le b \le \left\lfloor \frac{r}{G} \right\rfloor $$
此时 和 的范围为:原问题转化为:在区间 内找两个互质的数 (,),使得 最大,且 尽量小。
2. 贪心策略
为了最大化距离,我们想让 尽量小, 尽量大,即尝试 ,。
- 如果 ,则 即为答案。
- 否则,需要稍微调整 或 ,使得它们互质。由于只相差一点点,距离几乎最大。
3. 调整范围
从最大距离开始,依次尝试距离减 、减 等。
$$(L + i, R - (k - i)) \quad \text{for } i = 0,1,\dots,k $$
对于距离 ,可能的数对为:即固定 和 的和为 ,差值最大为 。
因为 可能很大( 级别),不能枚举所有 。但可以证明, 只需要尝试到大约 即可,因为当区间长度足够时,一定能找到互质对。
4. 为什么 很小
在区间 和 中,一定存在一对互质的数(通过容斥原理可证)。
因此,最多需要尝试 次距离递减(),每次检查最多 个数对,总复杂度 可接受。
算法步骤
- 读入 。
- 计算 ,。
若 ,则无解。 - 从 开始,枚举距离减小量:
- 尝试所有 ,设 ,。
- 检查是否 ,且 。
- 如果找到,输出 ,。
- 如果尝试完 到某个上限(如 )仍未找到,输出
-1 -1。
时间复杂度
每个测试用例检查 个数对,每次检查 为 ,总复杂度 , 可接受。
C++ 代码实现
#include <bits/stdc++.h> using namespace std; using ll = long long; ll gcd(ll a, ll b) { while (b) { a %= b; swap(a, b); } return a; } void solve() { ll l, r, g; cin >> l >> r >> g; // 找到区间内第一个和最后一个能被 g 整除的数 ll L = (l + g - 1) / g; // ceil(l / g) ll R = r / g; // floor(r / g) if (L > R) { cout << "-1 -1\n"; return; } // 尝试距离从大到小 for (ll k = 0; k <= 60; k++) { // 距离 = R - L - k for (ll i = 0; i <= k; i++) { ll a = L + i; ll b = R - (k - i); if (a > b) continue; if (a < L || b > R) continue; if (gcd(a, b) == 1) { cout << a * g << " " << b * g << "\n"; return; } } } cout << "-1 -1\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
验证样例
输入:
4 4 8 2 4 8 3 4 8 4 5 7 6输出:
4 6 -1 -1 4 8 6 6与题目输出一致。
补充说明
- 代码中 的上限设为 是安全的,实际所需往往更小。
- 注意使用
long long避免溢出。 - 当 很大时, 和 可能很小,但算法依然正确。
- 1
信息
- ID
- 7064
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者