codeforces1451 E. Bitwise Queries(位运算妙用)

E1. Bitwise Queries (Easy Version)

a + b = ( a & b ) + ( a ∣ b ) a+b=(a\&b)+(a|b) a+b=(a&b)+(ab)
根据上述式子用 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 a1ai=x于是 a i = x ⊕ a 1 a_i=x\oplus a_1 ai=xa1可使用 n − 3 n-3 n3 ⊕ \oplus 操作得出答案
共计 n + 3 n+3 n+3次。。。
大佬题解
a + b = ( a ⊕ b ) + 2 × ( a & b ) a+b=(a\oplus b)+2×(a\&b) a+b=(ab)+2×(a&b)
如果已知 a 1 ⊕ a 2 , a 2 ⊕ a 3 a_1\oplus a_2,a_2 \oplus a_3 a1a2,a2a3那么 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) a1a3=(a1a2)(a2a3)
那么只需用 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<n1,由此数组有两种情况

  • 数组元素不重复,各不相同
  • 数组元素重复

①对于数组元素重复的情况,我们首先进行 n − 1 n-1 n1 x 1 ⊕ x i x_1\oplus x_i x1xi将异或值记入数组 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 xix1=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;
}

要加油哦~

猜你喜欢

转载自blog.csdn.net/Fighting_Peter/article/details/110096397