1. 程式人生 > 實用技巧 >[CF1451E1] Bitwise Queries (Easy Version) - 構造

[CF1451E1] Bitwise Queries (Easy Version) - 構造

Description

互動題,用不超過 \(n+2\) 次操作猜出一個長度為 \(n\) 的陣列,每次可以指定兩個不同的下標,詢問這兩個位置的數的 AND 或 OR 或 XOR。

Solution

一個直觀的思路是先猜出一小部分數,進而通過異或操作得出剩下的。

猜一個是不行的,猜兩個似乎也是不行的。

考慮猜三個,我們可以用五個“方程”去求解前三個數,至於選取怎樣的組合有很多種方案,可以寫個暴力程式嘗試幾次或者手玩一下。

#include <bits/stdc++.h>
using namespace std;

void clamp(int &x)
{
    x = x != 0;
}

bool check(int a, int b, int c, int u, int v, int x, int y, int z)
{
    clamp(a);
    clamp(b);
    clamp(c);
    clamp(u);
    clamp(v);
    clamp(x);
    clamp(y);
    clamp(z);
    return u == (a ^ b) && v == (b ^ c) && x == (a | c) && y == (a & b) && z == (b & c);
}

void solve(int &a, int &b, int &c, int u, int v, int x, int y, int z, int bm)
{
    for (int ia = 0; ia < 2; ia++)
    {
        for (int ib = 0; ib < 2; ib++)
        {
            for (int ic = 0; ic < 2; ic++)
            {
                if (check(ia, ib, ic, (u & bm) > 0, (v & bm) > 0, (x & bm) > 0, (y & bm) > 0, (z & bm) > 0))
                {
                    a += bm * ia;
                    b += bm * ib;
                    c += bm * ic;
                    return;
                }
            }
        }
    }
}

int main()
{
    int u = 0, v = 0, x = 0, y = 0, z = 0, n;
    cin >> n;
    cout << "XOR 1 2 \nXOR 2 3 \nOR 1 3 \nAND 1 2 \nAND 2 3"
         << endl;
    cout.flush();
    cin >> u >> v >> x >> y >> z;

    int *a = new int[n + 5];

    for (int i = 1; i <= 3; i++)
        a[i] = 0;

    for (int i = 1; i < n; i *= 2)
        solve(a[1], a[2], a[3], u, v, x, y, z, i);

    for (int i = 4; i <= n; i++)
    {
        cout << "XOR 1 " << i << endl;
        cout.flush();
        cin >> a[i];
        a[i] ^= a[1];
    }

    cout << "! ";
    for (int i = 1; i <= n; i++)
        cout << a[i] << " ";
    cout << endl;
}