E1. Bitwise Queries (Easy Version)
a + b = ( a & b ) + ( a ∣ b ) a+b=(a\&b)+(a|b) a+b=(a&b)+(a∣b)
根据上述式子用 3 3 3次$&和 3 3 3次 ∣ | ∣操作求出 a 1 + a 2 , a 2 + a 3 , a 1 + a 3 a_1+a_2,a_2+a_3,a_1+a_3 a1+a2,a2+a3,a1+a3由此得出 a 1 , a 2 , a 3 a_1,a_2,a_3 a1,a2,a3
根据 a 1 ⊕ a i = x a_1\oplus a_i=x a1⊕ai=x于是 a i = x ⊕ a 1 a_i=x\oplus a_1 ai=x⊕a1可使用 n − 3 n-3 n−3次 ⊕ \oplus ⊕操作得出答案
共计 n + 3 n+3 n+3次。。。
大佬题解
a + b = ( a ⊕ b ) + 2 × ( a & b ) a+b=(a\oplus b)+2×(a\&b) a+b=(a⊕b)+2×(a&b)
如果已知 a 1 ⊕ a 2 , a 2 ⊕ a 3 a_1\oplus a_2,a_2 \oplus a_3 a1⊕a2,a2⊕a3那么 a 1 ⊕ a 3 = ( a 1 ⊕ a 2 ) ⊕ ( a 2 ⊕ a 3 ) a_1\oplus a_3=(a_1\oplus a_2)\oplus (a_2\oplus a_3) a1⊕a3=(a1⊕a2)⊕(a2⊕a3)
那么只需用 5 5 5次就可以知道 a 1 , a 2 , a 3 a_1,a_2,a_3 a1,a2,a3最终用 n + 2 n+2 n+2次得出答案。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=998244353;
const int N=100010;
int x,y,z;
void prework()
{
int ab1,ab2,ac1,ac2,bc1,bc2;
printf("XOR 1 2\n");
fflush(stdout);
cin>>ab1;
printf("AND 1 2\n");
fflush(stdout);
cin>>ab2;
printf("XOR 1 3\n");
fflush(stdout);
cin>>ac1;
printf("AND 1 3\n");
fflush(stdout);
cin>>ac2;
bc1 = ab1 ^ ac1;
printf("AND 2 3\n");
fflush(stdout);
cin>>bc2;
x=ab1+2*ab2;
y=ac1+2*ac2;
z=bc1+2*bc2;
}
int main()
{
IO;
int T=1;
//cin>>T;
while(T--)
{
int n;
cin>>n;
vector<int> ans(n+1);
prework();
ans[1]=(x+y-z)/2;
ans[2]=(x+z-y)/2;
ans[3]=(y+z-x)/2;
for(int i=4;i<=n;i++)
{
int tmp;
printf("XOR 1 %d\n",i);
fflush(stdout);
cin>>tmp;
ans[i]=tmp^ans[1];
}
cout<<"! ";
for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
cout<<'\n';
}
return 0;
}
E2. Bitwise Queries (Hard Version)
大佬题解
同样只要我们能确认一个值,其余的值都能通过异或来得到。由此我们目标是确定一个值。
注意到 0 < x i < n − 1 0<x_i<n-1 0<xi<n−1,由此数组有两种情况
- 数组元素不重复,各不相同
- 数组元素重复
①对于数组元素重复的情况,我们首先进行 n − 1 n-1 n−1次 x 1 ⊕ x i x_1\oplus x_i x1⊕xi将异或值记入数组 a i a_i ai,不难发现其中肯定存在相同的值,只要记录相同值的位置 i , j i,j i,j那么只需要进行一次 x i & x j x_i\&x_j xi&xj即可知道 x i x_i xi和 x j x_j xj,那么就能根据 a i a_i ai或者 a j a_j aj得出 x 1 x_1 x1进而得出答案。操作 n n n次
②如果不存在那么一定有某个数与第一个数相差1, a i = 1 a_i=1 ai=1,即 x i ⊕ x 1 = 1 x_i\oplus x_1=1 xi⊕x1=1,于是 不难得知 x 1 x_1 x1和 x i x_i xi分别是 ( x 1 & x i ) (x_1\& x_i) (x1&xi)和 ( x 1 & x i ) ⊕ 1 (x_1\& x_i)\oplus1 (x1&xi)⊕1
然后随便找一个与第一个数奇偶性相同的数( a i & 1 = 0 a_i\&1=0 ai&1=0)用一次 & \& &操作 x 1 & x i x_1\&x_i x1&xi的奇偶性即是 x 1 x_1 x1的奇偶性,于是可以得出 x 1 x_1 x1。操作 n + 1 n+1 n+1次
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=998244353;
const int N=200010;
int a[N];
map<int,int> pos;
int main()
{
//IO;
int T=1;
//cin>>T;
while(T--)
{
int n;
cin>>n;
pos.clear();
pos[0]=1;
int k=0,v;
for(int i=2;i<=n;i++)
{
printf("XOR 1 %d\n",i);
fflush(stdout);
cin>>a[i];
if(pos[a[i]]&&!k)
{
printf("AND %d %d\n",pos[a[i]],i);
fflush(stdout);
cin>>v;
k=i;
}
pos[a[i]]=i;
}
if(k) a[1]=a[k]^v;
else
{
printf("AND 1 %d\n",pos[1]);
fflush(stdout);
cin>>a[1];
for(auto t:pos)
{
if((t.first&1)||t.second==1) continue;
printf("AND 1 %d\n",t.second);
fflush(stdout);
int c; cin>>c;
if(c&1) a[1]^=1;
break;
}
}
cout<<"! "<<a[1]<<' ';
for(int i=2;i<=n;i++)
cout<<(a[i]^a[1])<<' ';
cout<<'\n';
}
return 0;
}
要加油哦~