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;
}

浙公网安备 33010602011771号