异或
jzoj 2298
题目大意:
定义 n b nb nb数对 a , b a,b a,b为 g c d ( a , b ) = a b gcd(a,b)=a^b gcd(a,b)=ab的数对,问不大于 n n n的 n b nb nb数对有多少对
输入样例#1
12
输出样例#1
8
输入样例#2
123456
输出样例#2
214394
数据范围
测试点 | 数据规模 |
---|---|
1 | 10 |
2 | 100 |
3 | 1000 |
4 | 5000 |
5 | 10000 |
6 | 100000 |
7 | 500000 |
8 | 1000000 |
9 | 5000000 |
10 | 20000000 |
解题思路:
我们第一个想到的就是暴力枚举每一个数对,然后判断,时间复杂度
o
(
n
2
l
o
g
n
)
o(n^2log_n)
o(n2logn)会TLE
因为
a
x
o
r
b
=
c
a\ xor\ b=c
a xor b=c,则
a
x
o
r
c
=
b
a\ xor\ c=b
a xor c=b,所以我们可以枚举c,然后在枚举a是c的几倍,然后用公式求出b,然后再求gcd,判断是否和c一样,时间复杂度
o
(
n
(
l
o
g
n
)
2
)
o(n(log_n)^2)
o(n(logn)2),也会TLE
我们可以经过证明得知b=a-c
证明:
首先
a
−
b
⩽
a
x
o
r
b
a-b\leqslant a\ xor\ b
a−b⩽a xor b
我们距离两个二进制数:
10110
10110
10110
11000
11000
11000
他们相减是
2
2
2
x
o
r
xor
xor是14
我们可以发现
x
o
r
xor
xor是不同位的和
而相减是加某些不同位,再减某些不同位,最大就是所有不同位加,也不大于
x
o
r
xor
xor
所以
a
−
b
⩽
a
x
o
r
b
a-b\leqslant a\ xor\ b
a−b⩽a xor b
然后我们可以发现
a
−
b
⩽
c
a-b\leqslant c
a−b⩽c
我们也列两个例子:
a
=
12
a=12
a=12
b
=
9
b=9
b=9
c
=
3
c=3
c=3
我们设
a
s
=
a
/
c
=
4
as=a/c=4
as=a/c=4
b
s
=
b
/
c
=
3
bs=b/c=3
bs=b/c=3
因为a,b都是c的倍数,所以
a
−
b
=
a
s
∗
c
−
b
s
∗
c
=
(
a
s
−
b
s
)
∗
c
a-b=as*c-bs*c=(as-bs)*c
a−b=as∗c−bs∗c=(as−bs)∗c
因为
a
a
a不等于
b
b
b
所以
a
s
−
b
s
⩾
1
as-bs\geqslant 1
as−bs⩾1
所以
(
a
s
−
b
s
)
∗
c
⩾
c
(as-bs)*c\geqslant c
(as−bs)∗c⩾c
所以
a
−
b
⩾
c
a-b\geqslant c
a−b⩾c
假设存在
c
<
a
−
b
c<a-b
c<a−b
则
c
<
a
−
b
⩽
a
x
o
r
b
c<a-b\leqslant a\ xor\ b
c<a−b⩽a xor b
不满足
c
=
a
x
o
r
b
c=a\ xor\ b
c=a xor b
所以
c
=
a
−
b
c=a-b
c=a−b
所以
b
=
a
−
c
b=a-c
b=a−c
因此
g
c
d
(
a
,
b
)
=
g
c
d
(
a
,
a
−
c
)
=
c
gcd(a,b)=gcd(a,a-c)=c
gcd(a,b)=gcd(a,a−c)=c
所以我们只需判断是否有
c
=
a
x
o
r
b
c=a\ xor \ b
c=a xor b即可
代码:
#include<cstdio>
using namespace std;
int n,a,b,ans;
int main()
{
scanf("%d",&n);
for (int i=1;i<=(n>>1);++i)
for (int j=2;i*j<=n;++j)
{
a=i*j;//求出a
b=a-i;//相减得到b
if (i==(a^b))//判断c是否等于a^b
ans++;
}
printf("%d",ans);
}