Problem: icpc2024_asia_kunming_k
Difficulty: hard
Categories: bit, math
Time limit: 1000 ms, memory limit: 1024 MB

Did you know? During the selection of ISIJ contestants, ISTJs and ISFJs don’t get extra points.

This is an interactive problem.

Kevin is dissatisfied with his MBTI, so he asked Doraemon for a magical machine: the MBTI converter.

The MBTI converter can convert the MBTI attributes of 8 people at a time. It will generate a “random” new MBTI for all individuals based on their initial MBTIs and a 32-bit key $k$ .

Kevin carefully studied this machine and found that the “random” MBTI it generates actually follows a certain pattern. The machine mainly includes three basic structures that shuffle the MBTI: “ xor”, “perm”, and “mix”. Each of these structures takes the MBTIs of 8 individuals as input and outputs 8 MBTIs as a result. In each structure, the input 8 MBTIs are denoted as $i n _ { 0 } , i n _ { 1 } , i n _ { 2 } , \cdots , i n _ { 7 }$ and the output 8 MBTIs are denoted as $o u t _ { 0 } , o u t _ { 1 } , o u t _ { 2 } , \cdot \cdot \cdot , o u t _ { 7 }$ . For convenience, Kevin replaces each MBTI with a hexadecimal number according to the following table.

<table><tr><td rowspan=1 colspan=1>INFP</td><td rowspan=1 colspan=1>INFJ</td><td rowspan=1 colspan=1>INTP</td><td rowspan=1 colspan=1>INTJ</td><td rowspan=1 colspan=1>ISFP</td><td rowspan=1 colspan=1>ISFJ</td><td rowspan=1 colspan=1>ISTP</td><td rowspan=1 colspan=1>ISTJ</td></tr><tr><td rowspan=1 colspan=1>0</td><td rowspan=1 colspan=1>1</td><td rowspan=1 colspan=1>2</td><td rowspan=1 colspan=1>3</td><td rowspan=1 colspan=1>4</td><td rowspan=1 colspan=1>5</td><td rowspan=1 colspan=1>6</td><td rowspan=1 colspan=1>7</td></tr><tr><td rowspan=1 colspan=1>ENFP</td><td rowspan=1 colspan=1>ENFJ</td><td rowspan=1 colspan=1>ENTP</td><td rowspan=1 colspan=1>ENTJ</td><td rowspan=1 colspan=1>ESFP</td><td rowspan=1 colspan=1>ESFJ</td><td rowspan=1 colspan=1>ESTP</td><td rowspan=1 colspan=1>ESTJ</td></tr><tr><td rowspan=1 colspan=1>8</td><td rowspan=1 colspan=1>9</td><td rowspan=1 colspan=1>a</td><td rowspan=1 colspan=1>b</td><td rowspan=1 colspan=1>C</td><td rowspan=1 colspan=1>d</td><td rowspan=1 colspan=1>e</td><td rowspan=1 colspan=1>f</td></tr></table>

# “xor” Structure:

The xor structure flips certain attributes of the MBTI based on the key $k$ .

Let $k _ { j }$ be the $j$ -th binary bit of the key $k$ ( $0 \leq j < 3 2$ ). The functionality of the xor structure can be expressed as:

$$
o u t _ { i } = i n _ { i } \oplus ( \overline { { k _ { 4 i + 3 } k _ { 4 i + 2 } k _ { 4 i + 1 } k _ { 4 i } } } ) _ { 2 }
$$

where $\bigoplus$ denotes the bitwise XOR1.

# “perm” Structure:

The perm structure replaces the MBTI, where each MBTI is replaced by another fixed MBTI.

The functionality of the perm structure can be expressed as:

$$
o u t _ { i } = p _ { i n _ { i } }
$$

where $p$ is a fixed array of length 16 with the following values:

<table><tr><td rowspan=1 colspan=1>P0</td><td rowspan=1 colspan=1>p1</td><td rowspan=1 colspan=1>P2</td><td rowspan=1 colspan=1>p3</td><td rowspan=1 colspan=1>P4</td><td rowspan=1 colspan=1>P5</td><td rowspan=1 colspan=1>p6</td><td rowspan=1 colspan=1>P7</td><td rowspan=1 colspan=1>p8</td><td rowspan=1 colspan=1>p9</td><td rowspan=1 colspan=1>P10</td><td rowspan=1 colspan=1>P11</td><td rowspan=1 colspan=1>P12</td><td rowspan=1 colspan=1>P13</td><td rowspan=1 colspan=1>P14</td><td rowspan=1 colspan=1>P15</td></tr><tr><td rowspan=1 colspan=1>7</td><td rowspan=1 colspan=1>0</td><td rowspan=1 colspan=1>5</td><td rowspan=1 colspan=1>6</td><td rowspan=1 colspan=1>b</td><td rowspan=1 colspan=1>f</td><td rowspan=1 colspan=1>4</td><td rowspan=1 colspan=1>3</td><td rowspan=1 colspan=1>1</td><td rowspan=1 colspan=1>d</td><td rowspan=1 colspan=1>C</td><td rowspan=1 colspan=1>e</td><td rowspan=1 colspan=1>8</td><td rowspan=1 colspan=1>9</td><td rowspan=1 colspan=1>a</td><td rowspan=1 colspan=1>2</td></tr></table>

# “mix” Structure:

The mix structure is used to mix the MBTIs of different people, with each output determined by two inputs.

The mix structure requires an intermediate array $t$ of length 8, defined as:

$$
t _ { i } = \left\{ { \begin{array} { l l } { i n _ { i } \ll 1 } & { 0 \leq i n _ { i } < 8 } \\ { ( ( i n _ { i } \oplus 8 ) \ll 1 ) \oplus 3 } & { 8 \leq i n _ { i } < 1 6 } \end{array} } \right.
$$

where $\bigoplus$ denotes the bitwise XOR $\cdot ^ { 1 }$ and $\ll$ denotes logical left shift of four binary digits2.

The functionality of the mix structure can be expressed as:

$$
o u t _ { i } = i n _ { i \gg 1 } \oplus \left( t _ { ( i \gg 1 ) \oplus 1 } \right)
$$

where $\bigoplus$ denotes the bitwise XOR $\cdot ^ { 1 }$ , and $\ggg$ denotes circular right shift of three binary digits3.

The initial 8 MBTIs will sequentially go through 19 structures to produce the final output of 8 MBTIs. These structures are: xor, perm, mix, xor, perm, mix, xor, perm, mix, xor, perm, mix, xor, perm, mix, xor, perm, mix, xor, which is six consecutive rounds of “xor, perm, mix” followed by an “xor”.

Users of this machine typically hope to obtain a specific MBTI. Unfortunately, when Doraemon built this machine, he encapsulated the key $k$ inside the machine and refused to tell Kevin the value of the key. Thus, Kevin turned to you, the clever one. Kevin hopes you can construct some inputs (not exceeding 4096, or the machine may be damaged), test run to obtain the corresponding outputs, and then analyze the value of the key. This way, he can write a program to predict the output for each input, allowing everyone to get their desired MBTI.

Can you accomplish this task?

1 Bitwise XOR refers to performing the modulo 2 addition operation on each corresponding bit of two binary numbers. For example: $( 0 0 1 1 ) _ { 2 } \oplus ( 0 1 0 1 ) _ { 2 } = ( 0 1 1 0 ) _ { 2 }$ .

2 $x \ll y$ means to logically left shift the binary number $x$ by $y$ bits, discarding the overflow and filling the vacated parts with 0. For example: $( 1 1 0 0 ) _ { 2 } \ll 1 = ( 1 0 0 0 ) _ { 2 }$ , $( 1 0 0 1 ) _ { 2 } \ll 1 = ( 0 0 1 0 ) _ { 2 }$ .

3 $x \gg y$ means to circularly right shift the binary number $x$ by $y$ bits. For example: $( 1 0 1 ) _ { 2 } \gg 1 =$ $( 1 1 0 ) _ { 2 }$ , $( 1 1 0 ) _ { 2 } \gg 1 = ( 0 1 1 ) _ { 2 }$ .

# Interaction Protocol

To run the MBTI converter, please output “? in7in6in5in4in3in2in1in0” ( $i n _ { i } \in \{ 0 - 9 , a - f \} )$ , where $i n _ { i }$ is the hexadecimal value corresponding to the $i$ -th input MBTI. You may perform this operation at most 4096 times. After flushing your output, please read the output of the MBTI converter in the format “out7out6out5out4out3out2out1out0” $( o u t _ { i } \in \{ 0 - 9 , a - f \} )$ .

To answer for the value of $k$ , please output “! $k ^ { \prime \prime }$ ( $0 \leq k < 2 ^ { 3 2 }$ ), where $k$ is the decimal representation of the value you believe the key $k$ to be. You may perform this operation at most once. After performing the operation, you should exit your program immediately.

If you run the MBTI converter more than 4096 times, or if your output contains invalid characters, the interactor will output “-1”. Upon receiving such a response, you should immediately exit your program, and you will receive a “Wrong Answer” result. Otherwise, the result is uncertain, as you will attempt to read data from a closed output stream.

To flush your output, you can use:

• fflush(stdout) (if you use printf) or cout.flush() (if you use cout) in C and C++.   
• System.out.flush() in Java and Kotlin.   
• stdout.flush() in Python.

# Example

<table><tr><td>standard input</td><td>standard output</td></tr><tr><td>acf7e10b 105092e0</td><td>？ 04f37255 ？ 9090cfca</td></tr></table>

# Note

The following information might be helpful when solving the problem:

1. There are no spaces between the $i n _ { i }$ s, $o u t _ { i }$ s, so please do not output extra spaces. The output is not a hexadecimal number, so do not ignore leading 0s that may exist.   
2. The range of $k$ is $[ 0 , 2 ^ { 3 2 } - 1 ]$ , so please be careful to avoid outputting negative numbers when outputting the answer.   
3. The attachment for this problem includes “interact.hpp”, which you may need for local debugging. For its usage, you can refer to the file “local_test_example.cpp” provided in the attachment.   
4. The interactor is not adaptive. That is, the value of $k$ in the interactor is fixed before the interaction begins and will not change according to your interactions.   
5. There are 64 tests for this problem in total.

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;





static const int P[16] = {7, 0, 5, 6, 0xb, 0xf, 4, 3, 1, 0xd, 0xc, 0xe, 8, 9, 0xa, 2};


static long long HIDDEN_K = 0;
static int queries = 0;
static const int QUERY_LIMIT = 4096;




void log_metrics() {
    
    
    try {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << QUERY_LIMIT << endl;
    } catch (...) {}
}

void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}




int hex2int(char c) {
    if (c >= '0' && c <= '9') return c - '0';
    if (c >= 'a' && c <= 'f') return c - 'a' + 10;
    if (c >= 'A' && c <= 'F') return c - 'A' + 10;
    return -1;
}

char int2hex(int v) {
    if (v >= 0 && v <= 9) return '0' + v;
    if (v >= 10 && v <= 15) return 'a' + (v - 10);
    return '?';
}




void run_machine(vector<int>& state, long long k) {
    
    
    
    
    for (int round = 0; round < 6; ++round) {
        
        
        for (int i = 0; i < 8; ++i) {
            
            int sub = (k >> (4 * i)) & 0xF;
            state[i] ^= sub;
        }

        
        
        for (int i = 0; i < 8; ++i) {
            state[i] = P[state[i]];
        }

        
        
        vector<int> t(8);
        for (int i = 0; i < 8; ++i) {
            if (state[i] < 8) {
                t[i] = (state[i] << 1) & 0xF;
            } else {
                
                int val = state[i];
                val ^= 8;
                val <<= 1;
                val &= 0xF; 
                val ^= 3;
                t[i] = val;
            }
        }
        
        vector<int> next_state(8);
        for (int i = 0; i < 8; ++i) {
            
            
            int idx_shifted = ((i >> 1) | ((i & 1) << 2)) & 0x7;
            
            int term1 = state[idx_shifted];
            
            int term2 = t[idx_shifted ^ 1];
            
            next_state[i] = term1 ^ term2;
        }
        state = next_state;
    }
    
    
    for (int i = 0; i < 8; ++i) {
        int sub = (k >> (4 * i)) & 0xF;
        state[i] ^= sub;
    }
}




int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);

    
    
    HIDDEN_K = inf.readLong();

    
    log_metrics();

    string token;
    while (cin >> token) {
        
        if (token == "!") {
            long long user_k;
            if (!(cin >> user_k)) {
                finish(_pe, "Expected key after '!'");
            }
            
            
            if (user_k == HIDDEN_K) {
                finish(_ok, "Correct key");
            } else {
                finish(_wa, "Incorrect key");
            }
        }
        
        
        string query_str;
        if (token == "?") {
            
            if (!(cin >> query_str)) {
                finish(_pe, "Expected query string after '?'");
            }
        } else {
            
            query_str = token;
        }

        
        
        if (queries >= QUERY_LIMIT) {
            cout << "-1" << endl;
            finish(_wa, "Query limit exceeded");
        }
        
        queries++;
        log_metrics(); 

        
        if (query_str.length() != 8) {
            cout << "-1" << endl;
            finish(_wa, "Invalid query string length (must be 8 hex chars)");
        }
        
        
        
        
        
        vector<int> state(8);
        bool valid = true;
        for (int i = 0; i < 8; ++i) {
            
            int val = hex2int(query_str[i]);
            if (val == -1) {
                valid = false;
                break;
            }
            state[7 - i] = val;
        }
        
        if (!valid) {
            cout << "-1" << endl;
            finish(_wa, "Invalid hex character in query");
        }

        
        run_machine(state, HIDDEN_K);

        
        
        
        for (int i = 0; i < 8; ++i) {
            cout << int2hex(state[7 - i]);
        }
        cout << endl; 
    }

    
    finish(_wa, "Unexpected EOF: solution exited without providing answer");
}


Adaptive interactor (C++):

Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);

    
    
    string mode = opt<string>("mode", "non");
    
    
    int seed_val = 0;
    if (argc > 1) {
        seed_val = atoi(argv[1]);
    }

    long long k;

    if (mode == "non") {
        
        
        if (seed_val == 1) k = 0;                            
        else if (seed_val == 2) k = 4294967295LL;            
        else if (seed_val == 3) k = 0xAAAAAAAA;              
        else if (seed_val == 4) k = 0x55555555;              
        else if (seed_val == 5) k = 0xFF00FF00;              
        else if (seed_val == 6) k = 0x00FF00FF;              
        else if (seed_val == 7) k = 0x0F0F0F0F;              
        else if (seed_val == 8) k = 0xF0F0F0F0;              
        else if (seed_val == 9) k = 0x12345678;              
        else if (seed_val == 10) k = (1LL << 31);            
        else {
            
            k = rnd.next(0LL, 4294967295LL);
        }
    } else {
        
        
        
        k = rnd.next(0LL, 4294967295LL);
    }

    
    cout << k << endl;

    return 0;
}