https://codeforces.com/contest/2039/problem/C1
帮助他计算整数 1≤y≤m的数量,使得 x≠y和 x⊕y是 x、 y或两者的 除数
一个数的除数一定小于等于自身的一半,即二进制下最高位与自身不同。注意到当y>2*x时,y的最高位与x不同,所以异或的结果一定大于y的一半。所以不可能是y的除数,然后大于y的一半意味着大于x,所以也不可能是x的除数。所以y>2*x时无解。只需要暴力枚举1~2x即可。
https://codeforces.com/contest/2039/problem/C2
帮助他计算整数 1≤y≤m的数量,使得$x \bigoplus y$ 可以被x或y整除。即是x或y的倍数。
分析:y在1~m内取值都有可能是答案了。所以不能暴力枚举。
分析当异或结果是x的倍数:则y的取值是$$x\bigoplus y = kx \\ \therefore y = kx \bigoplus x$$
只需要找哪些y在1~m内即可。需要用到如下两个异或性质:
异或是不进位的加法,所以$x\bigoplus y \leqslant x+y$
异或是不借位的减法,所以$x\bigoplus y \geqslant x-y$
因此,考虑m = kx + b;
则倍数小于等于k-1时,$(k-2)* x\leqslant y \leqslant k*x \leqslant m$,这些一定都能取到(除了1*x取不到,因为此时y=0)
对于倍数k,$(k-1)*x\leqslant y \leqslant (k+1)*x$ 有可能取不到,也有可能取到
对于倍数k+1,同理,可能取到也可能取不到。因此这两个特判一下即可。
接下来考虑异或结果是y的倍数:当y大于x时,一定取不到,因为$x\bigoplus y \leqslant y+x \leq 2y$
当y小于等于x时,暴力枚举即可。
考虑异或结果是x和y的倍数:即$x\bigoplus y \geqslant 2*max(x,y)$,只有一个解,即x==y。
所以最后答案使用容斥原理计算即可(注意当m小于x时不存在第三种情况)。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int x; ll m; cin >> x >> m;
// divisible by x
ll p = m - m % x;
ll ans = p / x - (x < p);
if ((x ^ p) >= 1 and (x ^ p) <= m) ++ans;
p += x;
if ((x ^ p) >= 1 and (x ^ p) <= m) ++ans;
// divisibly by y
for (int y = 1; y <= min(1LL * x, m); y++) {
ll cur = x ^ y;
if (cur % y == 0) {
++ans;
}
}
// divisible by both
if (x <= m) {
--ans;
}
cout << ans << '\n';
}
int32_t main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}