Codeforces Round #685 (Div. 2) 全文见:https://blog.csdn.net/qq_43461168/article/details/113175779
E. Bitwise Queries
题意:给定一个未知的数组。长度为n。值在[0,n-1]区间。可以进行询问,询问任意两个数的任意位运算的值。AND,OR,XOR。要求在n+2(easy)/n+1(hard)次操作只能给出原数组。
思路参考:https://blog.csdn.net/qq_45458915/article/details/109990408
思路:初看这个题。很容易想到。只要确定了数组中的某一个值。剩下的就可以直接异或得出。那就想办法获得a[1]的值就行了。
核心公式:a+b = (a^b)+2*(a&b)。 a ^c = (a^b)^(b^c)
有了这两个公式。我们可以选前三个数两两做异或和与运算。求出 a+b + a+c + b+c。也就是可以求出a+b+c。又因为已经求出了b+c。就可以求出a了。 但是求 a+b 要两次,b+c两次,a+c两次。就6次了。再加剩下的 n-3 个。就需要n+3次操作。 此时用公式2。就可以减少一次异或了。也就是只需要 ab,bc异或。 ac就已经是知道的了。所以总次数n+2。 E1就过了。 对于E2,要减少一次操作,就需要利用到题目给的数据的性质了。
如果 数据中有两个相同的值。那么,要么和a[1]相等,那么异或值等于0。这时候再做一次与运算。就可以求出a[1]了。 要么 a[i]^a[1] == a[j]^a[1]。这就说明a[i]和a[j]是相等的。那么,同样的。我们只需要对a[i]和a[j]做与运算,他们就求出来了。再根据和a[1]的异或值。就可以求出a[1]了。操作次数为n。
如果数据中没有重复值。又因为数据范围是[0,n-1]并且n是2的幂次。也就是说。一定会有一个数。和a[1]异或起来等于n-1,也就是二进制位全为1。并且a[1]和a[j]没有相同位。 也就是说 a[i]&a[1] == 0。有了这个再结合E1的解法。因为E1 需要两次异或和三次 与 可以求出三个值。而这里已经可以知道了其中一个 与 和两次异或 的值。 也就是再做两次与。总共5次操作。就可以求出a[1] 了。 于是就解出来。 操作次数为 n+1。
AC代码:
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
using namespace std;
const int N = 1e6+7;
const int mod = 1e9+7;
int t = 1,n,m,k;
int a[N];
int tmp[N];
int ask(string op,int i,int j){
cout<<op<<" "<<i<<" "<<j<<endl;
cout.flush();
int x;
cin>>x;
return x;
}
map<int,int> mp;
int zero = -1;
int same = -1;
int n_1 = -1;
signed main(){
//cin>>t;
while(t-- ){
cin>>n;
for(int i = 2 ; i <= n ; i ++){
tmp[i] = ask("XOR",1,i);
if(mp[tmp[i]]){
same = i;
}
if(tmp[i] == 0){
zero = i;
}
if(tmp[i] == n-1){
n_1 = i;
}
mp[tmp[i]] ++;
}
if(zero != -1){ // 有至少一个数和a[1] 相等
int now = ask("AND",1,zero);
a[1] = now;
}else if(same != -1){ // 有 a[2-n] 中有两个数相等
for(int i = 2 ; i <= n ; i ++){
if(tmp[i] == tmp[same]){
int now = ask("AND",i,same);
a[i] = now;
a[1] = tmp[i]^a[i];
break;
}
}
}else if(n_1){ // 有一个数 异或a[1] = n-1
int c = -1; // 随便找一个数 c
if(n_1+1 <= n) c = n_1+1;
else c = n_1-1;
int axorb = n-1,axorc = tmp[c],bxorc = axorb^axorc;
int aandb = 0,aandc = ask("AND",1,c),bandc = ask("AND",n_1,c);
int abc = (axorb+axorc+bxorc+2*(aandb+aandc+bandc))/2;
int bc = bxorc+2*bandc;
a[1] = abc - bc;
}
cout<<"! "<<a[1]<<" ";
for(int i = 2 ; i <= n ; i ++){
a[i] = tmp[i]^a[1];
cout<<a[i]<<" ";
}
cout<<endl;
cout.flush();
}
return 0;
}