0%

CodeTON Round 9 (Div. 1 + Div. 2, Rated, Prizes!)——C1. Shohag Loves XOR (Easy Version)

思路和官方题解应该差不多,但我自认为还是比他讲的清楚一点,其实就是一个对暴力法的上界优化

思路讲解

有一点是肯定的,d<=floor(p/2)d<=floor(p/2) dd 才可能被 pp 整除

当然这题肯定还是和位运算相关嘛,所以我们更关心的其实是 dd 的二进制最高位和 pp 是不一样的

然后我大概猜到是怎么一回事了。

只需要对暴力代码进行一些小小的改动就行

1
for(ll y=1;y<=min(m,change(x));++y) {

把循环上界改成 min(m,change(x))min(m,change(x) ) 就行

那这个 change(x)change(x) 是啥那?

1
2
3
4
5
6
7
8
9
inline ll change(ll x) {
ll res=1;
while (true) {
if(x==0)
return res*2;
x/=2;
res*=2;
}
}

其实很简单,就是 2(ceil(log2(x)))2**(ceil(log2(x))) 的意思(**是次方的意思),只不过写了个循环而已 。

然后我们来说我大概猜到什么了

yy 可以很大,相对来说 xx 就比较小,那么当 yy 很大的时候,d=d=xx^yy ( ^是异或的意思) 的高位完全是跟着 yy 走的,但这样的 dd 首先不可能被 xx 整除,其次也不可被y整除(我们前面看了,dd 的高位是不能和 yy 一样的)

当然这个 yy 要多大才会这样那?其实只要大到 yy 的最高位异或时不受 xx 影响就行了,也就是

y>=2(ceil(log2(x)))y>=2**(ceil(log2(x)))

其实异或还真和加法很像,一个高位的数异或低位的数几乎不会有什么影响。

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=static_cast<int>(2e5)+15;
int T;

inline ll change(ll x) {
ll res=1;
while (true) {
if(x==0)
return res*2;
x/=2;
res*=2;
}
}

signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>T;
while (T--) {
ll x,m;
cin>>x>>m;
ll ans=0;
for(ll y=1;y<=min(m,change(x));++y) {
ll div=x^y;
if(div==0)
continue;
if(x%div==0 || y%div==0) {
++ans;
}
}
cout<<ans<<endl;
}
return 0;
}

心路历程(WA,TLE,MLE……)

暴力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=static_cast<int>(2e5)+15;
int T;

signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>T;
while (T--) {
ll x,m;
cin>>x>>m;
ll ans=0;
for(ll y=1;y<=m;++y) {
ll div=x^y;
if(div==0)
continue;
if(x%div==0 || y%div==0) {
++ans;
}
}
cout<<ans<<endl;
}
return 0;
}