Problem: icpc2025_asia_bangkok_a
Difficulty: medium
Categories: graph
Time limit: 1000 ms, memory limit: 256 MB

Aboard the spaceship Skeld are you — the ship’s commander — along with $N$ crewmates. The voyage from Earth to Polus was meant to be peaceful... until it wasn’t. A series of strange incidents occurs: oxygen runs low, the reactor nearly melts down, the lights flicker, and the doors jam shut. Suspicion spreads — there might be impostors among us.

Moments of crisis were handled with the crewmates’ unity, but the tension lingered. Each crewmate now secretly suspects exactly one crewmate of being the impostor. Remarkably, no crewmate is suspected by more than one person. Formally, there exists a permutation $P$ of length $N$ , where $P [ i ]$ is the crewmate whom the $i$ -th crewmate suspects.

Overseeing this chaos from the commander’s room, you, however, are not actually concerned with finding the impostors. Rather, your only goal is to determine the hidden permutation $P$ .

Naturally, to achieve this, you may call emergency meetings. In each meeting, you can choose the order in which the crewmates speak.

Given a crewmate speaking, they will accuse the crewmate they suspect. If the speaker has not yet been marked as sus, their accusation is valid, and the accused crewmate becomes sus. However, if the speaker is already $\mathbf { \Delta } _ { \mathbf { \Delta } } \mathbf { \Delta } _ { \mathbf { \Delta } } \mathbf { \Delta } _ { \mathbf { \Delta } } \mathbf { \Sigma } _ { \mathbf { \Delta } } \mathbf { \Sigma } _ { \mathbf { \Delta } } \mathbf { \Sigma } _ { \mathbf { \Delta } } \mathbf { \Sigma } _ { \mathbf { \Delta } } \mathbf { \Sigma } _ { \mathbf { \Delta } }$ , their accusation is ignored.

Unfortunately, as the commander, you cannot attend the meetings yourself. Instead, after each meeting, the ship’s log reports the sus status of all crewmates as a binary array, where 1 indicates sus and 0 indicates not $\mathbf { { \mathit { s u s s } } }$ .

Since time is limited, you may hold at most 400 emergency meetings. Your task is to determine the hidden permutation $P$ within this limit.

# Interaction Protocol

Your program first reads a single integer $N$ ( $2 \leq N \leq 1 0 0$ ) — the number of crewmates.

Then, you may repeatedly perform queries (call emergency meetings). To make a query, print a line in the following format:

• ? q1 q2 . . . qN

Here, $( q _ { 1 } , q _ { 2 } , \ldots , q _ { N } )$ is the order in which the crewmates will speak during the meeting. The sequence must be a permutation of length $N$ .

After printing a query, flush the output and read a line containing $N$ integers:

• $s _ { 1 } ~ s _ { 2 } ~ . . . ~ s _ { N }$

Here, $s _ { i }$ indicates the status of the $i$ -th crewmate after the meeting ends:

• $s _ { i } = 0 - \mathrm { t h e } ~ i$ -th crewmate is not sus.   
• $s _ { i } = 1$ — the $i$ -th crewmate is sus.

# Each emergency meeting is independent; all crewmates start as not sus.

When you have determined the hidden permutation $P$ , print it in the following format:

• ! p1 p2 . . . pN

Printing the answer does not count as a query. After printing the final answer, your program should immediately terminate. Failure to do so may result in an undefined verdict.

You may perform at most 400 queries. If your program performs more than 400 queries or outputs an invalid format, you may receive a Wrong Answer verdict.

The interactor is not adaptive, which means that the hidden permutation does not depend on the queries you make.

After printing a query or an answer, do not forget to output the end of line and flush the output. Otherwise, you may get an Idleness Limit Exceeded verdict. To do this, use:

• fflush(stdout) or cout.flush() in C/C++;   
• System.out.flush() in Java and Kotlin;   
• sys.stdout.flush() in Python;

# Example

<table><tr><td>standard input</td></tr><tr><td></td></tr><tr><td>？123456</td></tr><tr><td>101110 001111</td></tr><tr><td>?243156</td></tr><tr><td>？654321 ？354216</td></tr></table>

# Note

For the first emergency meeting, the permutation $P$ is $[ 4 , 5 , 3 , 6 , 2 , 1 ]$ and the accusations go as follows:

• Crewmate 1 accuses crewmate 4. Crewmate 4 becomes sus.   
• Crewmate 2 accuses crewmate 5. Crewmate 5 becomes sus.   
• Crewmate 3 accuses crewmate 3. Crewmate 3 becomes sus.   
• Crewmate 4 accuses crewmate 6, but they are already sus, so it is ignored.   
• Crewmate 5 accuses crewmate 2, but they are already sus, so it is ignored.   
• Crewmate 6 accuses crewmate 1. Crewmate 1 becomes sus.   
• The ship reports the status of the crewmates as 1 0 1 1 1 0.

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




static long long queries = 0;
static long long query_limit = 400; 






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





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





static bool is_integer(const string& s) {
    if (s.empty()) return false;
    size_t i = 0;
    if (s[0] == '-') i = 1;
    if (i == s.size()) return false; 
    for (; i < s.size(); ++i) {
        if (!isdigit(s[i])) return false;
    }
    return true;
}




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

    
    int N = inf.readInt(2, 100, "N");
    vector<int> P(N + 1);
    vector<bool> p_seen(N + 1, false);
    for (int i = 1; i <= N; ++i) {
        P[i] = inf.readInt(1, N, format("P[%d]", i));
        if (p_seen[P[i]]) quitf(_fail, "Hidden input P is not a permutation");
        p_seen[P[i]] = true;
    }

    
    log_metrics();

    
    cout << N << endl;

    
    while (true) {
        string token;
        
        if (!(cin >> token)) {
            finish(_wa, "Unexpected EOF (expected query '?' or answer '!')");
        }

        if (token == "!") {
            
            vector<int> guess(N + 1);
            for (int i = 1; i <= N; ++i) {
                string t;
                if (!(cin >> t)) finish(_wa, "EOF reading answer permutation");
                if (!is_integer(t)) finish(_wa, "Answer token '" + t + "' is not an integer");
                try {
                    guess[i] = stoi(t);
                } catch (...) {
                    finish(_wa, "Answer integer out of range");
                }
            }
            
            
            bool ok = true;
            for (int i = 1; i <= N; ++i) {
                if (guess[i] != P[i]) {
                    ok = false;
                    break;
                }
            }
            
            if (ok) finish(_ok, "Correct permutation found");
            else finish(_wa, "Incorrect permutation");

        } else {
            
            queries++;
            
            
            if (queries % 10 == 0) log_metrics();
            
            
            if (queries > 200000) {
                finish(_pe, "Hard query limit exceeded (infinite loop protection)");
            }
            
            vector<int> Q;
            Q.reserve(N);

            
            
            if (token != "?") {
                if (!is_integer(token)) {
                    finish(_wa, "Invalid token '" + token + "' (expected '?' or integer)");
                }
                try {
                    Q.push_back(stoi(token));
                } catch (...) {
                    finish(_wa, "Query integer out of range");
                }
            }
            
            int needed = (token == "?") ? N : N - 1;
            for (int i = 0; i < needed; ++i) {
                string t;
                if (!(cin >> t)) finish(_wa, "EOF reading query");
                if (!is_integer(t)) finish(_wa, "Query token '" + t + "' is not an integer");
                try {
                    Q.push_back(stoi(t));
                } catch (...) {
                    finish(_wa, "Query integer out of range");
                }
            }
            
            
            if ((int)Q.size() != N) finish(_wa, "Query size mismatch");
            vector<bool> q_seen(N + 1, false);
            bool valid = true;
            for (int x : Q) {
                if (x < 1 || x > N || q_seen[x]) {
                    valid = false;
                    break;
                }
                q_seen[x] = true;
            }
            if (!valid) finish(_wa, "Query is not a valid permutation of 1..N");
            
            
            
            vector<int> sus(N + 1, 0);
            for (int u : Q) {
                if (sus[u]) continue; 
                int target = P[u];    
                sus[target] = 1;      
            }
            
            
            for (int i = 1; i <= N; ++i) {
                cout << sus[i] << (i == N ? "" : " ");
            }
            cout << endl; 
        }
    }
    
    return 0;
}


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");
    
    
    long long seed = atoll(argv[1]);

    int n;
    vector<int> p;

    
    if (seed == 1) {
        
        n = 2;
        p = {2, 1};
    } else if (seed == 2) {
        
        n = 100;
        p.resize(n);
        iota(p.begin(), p.end(), 1);
    } else if (seed == 3) {
        
        n = 100;
        p.resize(n);
        for (int i = 0; i < n; ++i) {
            p[i] = (i + 1) % n + 1;
        }
    } else if (seed == 4) {
        
        n = 100;
        p.resize(n);
        iota(p.begin(), p.end(), 1);
        for (int i = 0; i + 1 < n; i += 2) {
            swap(p[i], p[i+1]);
        }
    } else {
        
        
        if (rnd.next(4) > 0) n = 100;
        else n = rnd.next(2, 100);

        int type = rnd.next(3);
        if (type == 0) {
            
            p = rnd.perm(n, 1);
        } else if (type == 1) {
            
            p = rnd.perm(n, 1);
            
            for (int iter = 0; iter < 50; ++iter) {
                bool has_fixed = false;
                for (int i = 0; i < n; ++i) if (p[i] == i + 1) has_fixed = true;
                if (!has_fixed) break;
                shuffle(p.begin(), p.end());
            }
            
            for (int i = 0; i < n; ++i) {
                if (p[i] == i + 1) {
                    
                    int j = (i + 1) % n;
                    swap(p[i], p[j]);
                    
                    if (p[j] == j + 1) {
                        int k = (j + 1) % n;
                        swap(p[j], p[k]);
                    }
                }
            }
        } else {
            
            p.resize(n);
            vector<int> nodes(n);
            iota(nodes.begin(), nodes.end(), 1);
            shuffle(nodes.begin(), nodes.end());
            
            int idx = 0;
            while(idx < n) {
                int rem = n - idx;
                
                int len = rnd.next(1, min(rem, 15));
                
                
                if (rem - len == 1) len++; 
                
                
                for(int k = 0; k < len; ++k) {
                    p[nodes[idx + k] - 1] = nodes[idx + (k + 1) % len];
                }
                idx += len;
            }
        }
    }

    
    if (mode == "non") {
        
        cout << n << endl;
        println(p);
    } else {
        
        cout << n << endl;
    }

    return 0;
}