由题意
我们要统计1~N中有多少二元组(a,b)满足gcd(a,b) ==a XOR b
首先有如下性质:
1.a XOR b >= a-b (a >= b)
证明:(给个简单的证明 OI证明都不严谨的)
在二进制下
a XOR b :b某一位的1才对答案有影响,如果a那位为1那就相当于减,为0相当于加
a 减 b: 同样b的某一为的1才对答案影响,且a的那一位不管是0还是1,都是减
所以 a XOR b 一定 >= a-b
2. a - b >= gcd( a,b )
证明:
设gcd(a,b)=c
则a=c*x1,b=c*x2(x1,x2互质且大于等于1)x1>=x2
a - b = c*(x1 -x2)>= c
所以a XOR b >= a-b >= gcd(a,b)
而 a XOR b=gcd(a,b)
所以a XOR b = a - b = gcd (a,b)
到这里解法应该就有很多了,我只分享第一次想到的懒
令 gcd(a,b)=d,a=d*x1 ,b=d*x2
由上述等式得x1-x2=1;
所以我们外层枚举d,内层枚举b,(a直接得到),然后判断a XOR b 是否等于 a - b
代码如下
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=3e7; 4 int c[N+9];//c[i]表示i与1~i-1中共有多少对满足 5 void pre(){ 6 for(int d=1;d<=N;d++){ 7 for(int b=d;b<=N-d;b+=d){ 8 int a=b+d; 9 if((a^b)==(a-b))c[a]++; 10 } 11 } 12 for(int i=1;i<=N;i++)c[i]+=c[i-1];//求出前缀和 13 } 14 void work(){ 15 int T,n; 16 scanf("%d",&T); 17 for(int i=1;i<=T;i++){ 18 scanf("%d",&n); 19 printf("Case %d: %d ",i,c[n]); 20 } 21 } 22 int main(){ 23 pre(); 24 work(); 25 return 0; 26 }