题意:
求满足GCD(a,b) = a XOR b; 其中1<=b <=a<=n。1<= n <= 30000000.
思路:
异或:a XOR b = c 那么 a XOR c = b;
那么我们令GCD(a,b)= c; 这样 a 是 c 倍数。我们可以通过遍历c , 然后通过筛法,把c的倍数晒出当作a。求b如何求呢?
书上提供一种方法是利用a XOR c=b 然后用 gcd(a,b)=c 验证。但是这个方法是超时的,gcd是logn 级别的 总的时间复杂度,n*(logn)^2。这是我们不能接受的。
还有一种方法是证明b=a-c。这个证明还是不容易的 :
首先(a>b)gcd(a,b) = c <= a-b 其次要证明a ^ b >= a-b 。我们可以这样想,他们什么时候取等于,我们知道异或是相同为0,不同为1 那么 我们把a,b用二进制展开,这样我们a,b是每一位对应的,我们把所以不同的二进制位,全部变为ai = 1,bi = 0。这样我们知道,没有借位 那么a ^ b == a-b 。那么后面按照XOR序列的顺序变化,a-b变小,那么a ^ b >= a-b。从而c = a-b
参考:http://www.mamicode.com/info-detail-2490991.html
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
//#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int RA = 30000000;
int ans[RA + 5];
void Init(){
memset(ans,0,sizeof(ans));
for(int c = 1; c <= RA/2; ++c){
for(int a = c + c; a <= RA; a += c){
int b = a - c;
if((a ^ b) == c) ++ans[a];
}
}
for(int i = 2; i <= RA; ++i) ans[i] += ans[i - 1];
}
int main(){
Init();
//freopen("in.txt","r",stdin);
int T,N;
scanf("%d",&T);
for(int i = 1; i <= T; ++i){
scanf("%d",&N);
printf("Case %d: %d\n",i,ans[N]);
}
return 0;
}