11 收心赛2 T1 gcd&xor 题解

gcd & xor

题面

给定一个正整数 \(n\) ,求在 \([1,n]\) 有多少 \((a, b)\) 满足 \(\gcd (a, b) = a \oplus b\)

\(1 \le n \le 10^7\)

题解

这道题没做出来,主要原因是考试时想的方向错了,一直在想怎么通过巧妙的位运算算出答案,但正解却是利用转化和性质直接推出了很简单的一个式子

先想 \(O(n \log^2 n)\) 的做法

原式要求的是 \(a \oplus b = \gcd (a, b)\)\((a,b)\) 的数量

这个东西其实不太好求,但这个式子其实可以变个型,变成 \(a \oplus \gcd (a, b) = b\)

这样有什么好处?

我们可以先枚举 \(g\)\(a\) 的约数,\(b = a \oplus g\)

然后再判断一下 \(\gcd (a, b)\) 是不是等于 \(g\) 即可

然后再想 \(O(n \log n)\) 的做法

枚举 \(g\)\(a\) 的约数,\(b = a \oplus g\)

如果 \(a = b\)\(\gcd (a, b) \not= 0\) ,所以我们不考虑

如果 \(a \not= b\),假设 \(a > b\) ,那么 \(\gcd (a, b) \le a - b \le a \oplus b\)

因为 \(\oplus\) 可以看做不进位加法,不退位减法,所以 \(a - b \le a \oplus b\)

又因为更相减损术,所以 \(\gcd (a, b) = \gcd (b, a - b) \le a - b\)

\(g = a \oplus b\) ,若有 \(g = a - b\) ,那么 \((a, b)\) 即为合法的一组解

考虑证明,我们可以先将条件和要证明的结论罗列一下

已知 \(g \mid a,\ \gcd (a,b) \le a \oplus b,\ g = a - b\)

求证 \(g = \gcd (a, b)\)

因为 \(g \mid a\) ,所以 \(a = mg\)

又因为 \(a - b = g\) ,所以 \(b = (m - 1) g\)

所以 \(g \mid a \land g \mid b\) ,所以 \(g \le \gcd (a, b)\)

又因为 \(\gcd (a,b) \le a \oplus b = g\)

所以 \(g = \gcd (a, b)\)

证毕

所以我们可以枚举一个 \(a\) 的约数 \(g\)\(b = a \oplus g\) ,然后判断 \(g = a - b\) 是否成立即可

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

int main () {
    
    int n;
    cin >> n;
    int ans = (n - 1) / 2;
    for (int g = 2; g <= n; g ++) {
        for (int a = g * 2; a <= n; a += g) {
            int b = a ^ g;
            if (b > a) continue;
            if (g == a - b) {
                ans ++;
            }
        }
    }

    printf ("%d\n", ans);

    return 0;
}
posted @ 2025-08-28 14:18  michaele  阅读(24)  评论(0)    收藏  举报