题目大意:
题目链接:https://jzoj.net/senior/#main/show/100047
题目图片:
http://wx1.sinaimg.cn/mw690/0060lm7Tly1fy7gss4ijmj30j50cujrv.jpg
http://wx4.sinaimg.cn/mw690/0060lm7Tly1fy7gss4gyaj30j20asdfx.jpg
已知数组
a
a
a,两种操作:
- 将 x x x变成 x x o r a i x\ xor\ a_i x xor ai
- 将 x x x二进制下任意一位取反。
求从 x x x变成 y y y的最少步数。
思路:
如果我们有一个数
z
z
z使得
x
x
o
r
z
=
y
x\ xor\ z=y
x xor z=y,那么很明显的
z
z
z就是我们要求的答案。
反过来得
x
x
o
r
y
=
z
x\ xor\ y=z
x xor y=z。
所以,其实
x
x
x到
y
y
y的最少步数就是
0
0
0到
z
z
z的最少步数!
那么就从
0
0
0开始
B
F
S
BFS
BFS,求出不超过
z
=
m
a
x
{
1111111
}
z=max\{1111111\}
z=max{1111111}的答案(因为
x
o
r
xor
xor最大就是
1111111
1111111
1111111了)。然后就可以
O
(
1
)
O(1)
O(1)输出了。
思维好题。
代码:
#include <cstdio>
#include <queue>
#define ri register
using namespace std;
const int N=1200000;
int n,u,v,Q,a[N],s,t,ans[N];
bool vis[N];
char c;
int read()
{
u=0;
c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9')
u=(u<<3)+(u<<1)+c-48,c=getchar();
return u;
}
int write(int x)
{
if (x>9) write(x/10);
putchar(x%10+48);
}
void bfs()
{
queue<int> q;
q.push(0);
vis[0]=1;
while (q.size())
{
u=q.front();
q.pop();
for (ri int i=1;i<=n;i++) //选择每一个数xor
if (!vis[u^a[i]])
{
vis[u^a[i]]=1;
ans[u^a[i]]=ans[u]+1;
q.push(u^a[i]);
}
for (ri int i=0;i<=19;i++) //选择每一位取反
{
if ((u&(1<<i))==(1<<i)) v=u-(1<<i);
else v=u+(1<<i);
if (!vis[v])
{
vis[v]=1;
ans[v]=ans[u]+1;
q.push(v);
}
}
}
}
int main()
{
n=read();
Q=read();
for (ri int i=1;i<=n;i++)
a[i]=read();
bfs();
while (Q--)
{
s=read();
t=read();
write(ans[s^t]);
putchar(10);
}
return 0;
}