「Codeforces 1152C」Neko does Maths

题目链接:Codeforces 1152C

Neko 有两个整数 $a$ 和 $b$,他的目标是找到一个非负整数 $k$ 使得 $\operatorname{lcm}(a + k, b + k)$ 尽可能小。如果有 $k$ 有多组解,他会选择最小的一个。

数据范围:$1 \le a, b \le 10 ^ 9$。


Solution

我们将 $\operatorname{lcm}$ 转化为 $\gcd$:

$$ \begin{align*} \operatorname{lcm}(a + k, b + k) & = \frac{(a + k) \cdot (b + k)}{\gcd(a + k, b + k)} \\ & = \frac{(a + k) \cdot (b + k)}{\gcd(a + k, a - b)} \end{align*} $$

那么我们枚举 $\gcd$ 为 $d$,一定有 $d \mid (a - b)$,此时我们只需要求出最小的 $k$ 使得 $d \mid (a + k)$。直接更新答案即可。

时间复杂度:$\mathcal O(\sqrt{\lvert a - b \rvert})$。


Code

#include <cstdio>
#include <algorithm>

typedef long long LL;

int a, b;

std::pair<LL, int> calc(int d) {
    int k = (d - a % d) % d;
    return std::make_pair(1LL * (a + k) * (b + k) / std::__gcd(a + k, b + k), k);
}
int main() {
    scanf("%d%d", &a, &b);
    int n = (a > b ? a - b : b - a);
    if (n == 0) {
        printf("%d\n", 0);
        return 0;
    }
    std::pair<LL, int> ans = std::make_pair(1e18, 1e9);
    for (int i = 1; i * i <= n; i++) {
        ans = std::min(ans, std::min(calc(i), calc(n / i)));
    }
    printf("%d\n", ans.second);
    return 0;
}

发表评论