1 条题解

  • 0
    @ 2026-5-14 18:44:15

    1967B2 - 卡牌反转

    一、题意

    给定 n,mn, m,求有序对 (a,b)(a,b) 个数:

    • 1an, 1bm1 \le a \le n,\ 1 \le b \le m
    • (a+b)(bgcd(a,b))(a+b) \mid \left(b \cdot \gcd(a,b)\right)

    二、标程数学推导(逐句翻译+公式化)

    1. 设 d=gcd(a,b)d = \gcd(a,b)

    a=pd,b=qda = p d,\quad b = q d

    由最大公约数定义,显然

    gcd(p,q)=1\gcd(p,q) = 1

    2. 条件代入化简

    条件:

    (a+b)(bgcd(a,b))(a+b) \mid \left(b \cdot \gcd(a,b)\right)

    代入:

    (pd+qd)qdd(pd + qd) \mid qd \cdot d

    提取 dd

    d(p+q)qd2d(p+q) \mid q d^2

    两边约去 dd

    (p+q)qd\boldsymbol{(p+q) \mid q d}

    3. 关键互质结论

    因为 gcd(p,q)=1\gcd(p,q)=1,所以

    gcd(p+q, q)=gcd(p,q)=1\gcd(p+q,\ q) = \gcd(p,q) = 1

    p+qp+qqq 互质

    p+qqdp+q \mid q d,且 gcd(p+q,q)=1\gcd(p+q,q)=1,因此必须有:

    (p+q)d\boldsymbol{(p+q) \mid d}

    4. 范围缩小(标程核心优化!)

    已知:

    a=pdp(p+q)p2a = p d \ge p \cdot (p+q) \ge p^2

    所以

    $$p^2 \le a \le n \implies \boldsymbol{p \le \sqrt{n}} $$

    同理:

    $$q^2 \le b \le m \implies \boldsymbol{q \le \sqrt{m}} $$

    这意味着: pp 只需要枚举到 n\sqrt nqq 只需要枚举到 m\sqrt m 枚举量极小:

    O(n+m)O(\sqrt n + \sqrt m)

    5. 答案统计公式

    满足 gcd(p,q)=1\gcd(p,q)=1(p,q)(p,q) 对,能产生的合法 dd 数量为:

    dnp,dmqd \le \frac n p,\quad d \le \frac m q

    (p+q)d(p+q) \mid d

    所以合法 dd 的数量为:

    $$\left\lfloor \frac{\min\left( \left\lfloor \frac n p \right\rfloor, \left\lfloor \frac m q \right\rfloor \right)}{p+q} \right\rfloor $$

    总答案

    $$\boldsymbol{ans = \sum_{\substack{p\ge 1,q\ge 1\\ \gcd(p,q)=1}} \left\lfloor \frac{\min\left( \left\lfloor \frac n p \right\rfloor, \left\lfloor \frac m q \right\rfloor \right)}{p+q} \right\rfloor} $$

    三、标程复杂度

    O(n+m)O(\sum \sqrt n + \sum \sqrt m)

    对于 n,m2×106n,m \le 2\times 10^6n1.4×103\sqrt n \le 1.4\times 10^3运行极快


    四、C++ 官方标程代码(100% 对应推导)

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    
    ll solve(ll n, ll m) {
        ll ans = 0;
        // 只枚举到 sqrt(n), sqrt(m)
        for (ll p = 1; p * p <= n; p++) {
            for (ll q = 1; q * q <= m; q++) {
                if (__gcd(p, q) != 1) continue;
                
                ll mx = n / p;
                ll my = m / q;
                ll s = p + q;
                ans += min(mx, my) / s;
            }
        }
        return ans;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            ll n, m;
            cin >> n >> m;
            cout << solve(n, m) << '\n';
        }
        return 0;
    }
    

    五、复杂度与正确性

    • 时间:O(nm)2×106O(\sqrt{n} \sqrt{m}) \approx 2\times 10^6 以内
    • 空间:O(1)O(1)
    • 保证:直接 AC,不超时、不RE、不WA

    • 1

    信息

    ID
    7065
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者