1. 程式人生 > 其它 >Codeforces 1451E. Bitwise Queries(位運算性質)

Codeforces 1451E. Bitwise Queries(位運算性質)

技術標籤:2021寒假演算法練習Div2Codeforces補題

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; }