跳到主要内容

题解:CF2043D Problem about GCD

· 阅读需 3 分钟
Sintle
Developer

题目链接

题意简述

给出三个整数 l,r,Gl,r,G,要求找到一个数对 A,BA,B 满足 lABrl\le A\le B\le rgcd(A,B)=G\gcd (A,B) = G,并且满足 AB\left\vert A-B \right\vert 最大。

如果有多组解,选择 AA 的值最小的一个。

解题思路

首先 A,BA,B 肯定都是 GG 的倍数,所以直接将 l,rl,r 转化为 lG,rG\left\lceil \dfrac{l}{G} \right\rceil,\left\lfloor \dfrac{r}{G} \right\rfloor,在该区间内求最远互质点对,设为 (x,y)(x ,y),则 (A,B)=(x×G,y×G)(A,B)=(x\times G,y\times G)

关于如何求区间内最远互质点对,可以参考 Atcoder arc137_a站内链接)。

如果直接暴力枚举 xy\left\vert x-y \right\vertxx,理论复杂度达到了惊人的 O((rl)loga)O((r-l)\log a),看上去是不能通过的。

但是其实并不会遍历那么多次,参考上面给出的题解可知在题目给出的 1×10181\times 10^{18} 数据范围内复杂度并没有很高。

所以尽管并未算出实际复杂度期望,但是我们暴力枚举仍然可以通过本题。

参考代码

#include <bits/stdc++.h>
using namespace std;

long long T , l , r , g;

long long gcd(long long aa , long long bb) {return bb ? gcd(bb , aa % bb) : aa;}

void solve()
{
long long len = r - l;
while(len >= 0)
{
for(long long i = l ; i <= r - len ; i++) if(gcd(i , i + len) == 1) {cout << i * g << " " << (i + len) * g << '\n'; return;}
len--;
}
cout << -1 << " " << -1 << '\n';
}

int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
cin >> T;
while(T--)
{
cin >> l >> r >> g;
l += g - 1; l /= g; r /= g;
solve();
}
return 0;
}

补充

以下是不严谨的关于该代码时间复杂度的证明。

参考资料

证明

在维基百科的这一条目中提到,托马斯·雷·奈斯利使用了公式 R=logpnpn+1pnR=\dfrac{\log p_n}{\sqrt{p_{n+1}-p_n}} 来计算素数间隙与克拉梅尔猜想相契合的程度,对于现在已知最大的素数间隙, RR 的值依然保持在 1.131.13 左右。

因此该题目中最大的素数间隙(设其为 g(i)g(i),且 pip_i 表示最大的质数间隙对应的质数对中较小的那一个)在 (logpi1.13)2(\dfrac{\log p_i}{1.13})^2 左右,因此即使我们并不确定 ii 的具体值,g(i)g(i) 的值一定不会超过 (log1e181.13)2(\dfrac{\log 1e18}{1.13})^2,而该式的值约为 6060

在该题目中,能够构造出的最坏情况为 l,rl,r 分别距离 x,yx,yg(i)g(i),此时上述代码的时间复杂度为 g(i)2g(i)^2

又因为我们已经证明了 g(i)g(i) 的值并不会超过 6060,所以上述代码的最坏时间复杂度为 O(Tg(i)2)O(Tg(i)^2),不超过 3.6×1063.6\times 10^6,显然可以通过本题。