问题
分析
这道题是我自己做不出来的
记录下思路
这道题肯定不能同时枚举a,b,否则肯定TLE,所以只枚举a,然后计算b。
思路:这涉及到gcd和xor之间的关系,设
a
x
o
r
b
=
c
a\space xor\space b=c
a xor b=c,那么由异或的性质,可以得到
a
x
o
r
c
=
b
a\space xor\space c=b
a xor c=b。所以可以枚举a和它的因数c作为gcd,然后计算出b,最后验证是否有
g
c
d
(
a
,
b
)
=
c
gcd(a,b)=c
gcd(a,b)=c.这种做法的时间复杂度:枚举a和它的因数c是O(nlgn),然后gcd是O(lgn),所以总的是
O
(
n
(
l
o
g
n
)
2
)
O(n(logn)^2)
O(n(logn)2)
继续优化,发现满足
g
c
d
(
a
,
b
)
=
c
=
a
x
o
r
b
gcd(a,b)=c=a\space xor\space b
gcd(a,b)=c=a xor b的元素都满足a-b=c
证明:a-b<=a xor b且a-b>=c,c=gcd(a,b)=a xor b,所以a-b=c
所以,可以枚举a,c,计算b=a-c,验证b=a^c是否成立,时间时O(lgn)
#include <cstring>
#include <cstdio>
#include <vector>
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn=30000000+1;
int cnt[maxn],s[maxn]; //cnt:前缀,cnt[i],a=i时的情况数
int main(void){
//类似埃氏筛的枚举方式
for(int c=1;c<maxn;++c){ //枚举c
for(int a=c*2;a<maxn;a+=c){ //枚举a
if(a-c==(a^c)){
cnt[a]++;
}
}
}
for(int i=1;i<maxn;++i) s[i]=s[i-1]+cnt[i];
int T=0,kase=0,n=0;
scanf("%d",&T);
while(kase<T){
scanf("%d",&n);
printf("Case %d: %d\n",++kase,s[n]);
}
return 0;
}