C. Dora and C++

实际上,我们不仅可以加 \(a\),或者加 \(b\)

由于我们只在乎相对差,所以我们可以做减 \(a\),减 \(b\),加 \(\lvert a-b\rvert\) 等更多操作。

发现实际上,我们如果一直计算类似两个数相减的值,最终得到的一个数就会是 \(\gcd(a,b)\),这是由于辗转相除法。我们同样可以知道,所有数都是 \(\gcd(a,b)\) 的倍数。因此,考虑只对原数进行无限次加 \(\gcd(a,b)\) 的操作得到的答案和原问题的答案相等,也就是说,这两个问题等价。

接下来,求我们可以对每个数加或减 \(\gcd(a,b)\) 的答案。

两个数 \(x,y(x>y)\) 的差在模 \(\gcd(a,b)\) 意义下分别是 \((x-y) \bmod \gcd(a,b),\gcd(a,b)-(x-y) \bmod \gcd(a,b)\)

我们将所有 \(x \bmod \gcd(a,b)\) 从小到大排序作为 \(B\),然后最大值减最小值就是所有差全部取第一种的答案。

\(B_{n}-B_{1}\)

如果想取第二种,那么我们可以证明,只有寻找一个分割点,左边的全部加 \(\gcd(a,b)\),右边的全部不变才有可能取到答案。

\(\min\{B_{i}+\gcd(a,b)-B_{i+1}\}\)

两种情况继续取最小值。

// Problem: C. Dora and C++
// Contest: Codeforces - Codeforces Round 969 (Div. 2)
// URL: https://codeforces.com/contest/2007/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define int long long
#define upp(a, x, y) for (int a = x; a <= y; a++)
#define dww(a, x, y) for (int a = x; a >= y; a--)
#define pb(x) push_back(x)
#define endl '\n'
#define x first
#define y second
#define PII pair<int, int>
using namespace std;
const int N = 1e6 + 10, INF = 0x3f3f3f3f3f3f3f3f;
int ac[N], n, a, b;
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int tt;
    cin >> tt;
    while (tt--) {
        int ans = INF;
        cin >> n >> a >> b;
        int gcdd = __gcd(a, b);
        int maxn = -INF, minn = INF;
        upp(i, 1, n) {
            int x;
            cin >> x;
            ac[i] = x % gcdd;
        }
        sort(ac + 1, ac + 1 + n);
        ans = min(ans, ac[n] - ac[1]);
        upp(i, 1, n - 1) { ans = min(ans, ac[i] + gcdd - ac[i + 1]); }
        cout << ans << endl;
    }
    return 0;
}
posted @ 2025-03-06 17:09  PM_pro  阅读(14)  评论(0)    收藏  举报