Problem: icpc2024_kunming_invitational_k
Difficulty: medium
Categories: search
Time limit: 1000 ms, memory limit: 1024 MB

This is an interactive problem.

There is a hidden permutation of $n$ . Recall that a permutation of $n$ is a sequence where each integer from $1$ to $n$ (both inclusive) appears exactly once. Piggy wants to unravel the permutation with some queries.

Each query must consist of a sequence (not necessarily a permutation) with $n$ integers ranging from 1 to $n$ (both inclusive). Each query is answered with an integer $x$ , indicating the number of the positions where the corresponding element in Piggy’s query sequence matches that of the hidden permutation. For example, if the hidden permutation is $\{ 1 , 3 , 4 , 2 , 5 \}$ and the sequence Piggy asks is $\{ 2 , 3 , 5 , 2 , 5 \}$ , he’ll receive 3 as the answer.

As Piggy is busy recently, he gives this problem to you. Find the permutation with no more than 6666 queries.

# Input

There is only one test case in each test file.

The first line of the input contains an integer $n$ ( $1 \leq n \leq 1 0 ^ { 3 }$ ) indicating the length of the hidden permutation.

# Interaction Protocol

To ask a query, output one line. First output 0 followed by a space, then print a sequence of $n$ integers ranging from 1 to $n$ separated by a space. After flushing your output, your program should read a single integer $x$ indicating the answer to your query.

If you want to guess the permutation, output one line. First output 1 followed by a space, then print a permutation of $n$ separated by a space. After flushing your output, your program should exit immediately.

Note that the answer for each test case is pre-determined. That is, the interactor is not adaptive. Also note that your guess does not count as a query.

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.   
• stdout.flush() in Python.

# Example

<table><tr><td>standard input</td><td>standard output</td></tr><tr><td>5</td><td>031322</td></tr><tr><td>3</td><td>031522</td></tr><tr><td>4</td><td></td></tr><tr><td>2</td><td>035444</td></tr><tr><td></td><td>131524</td></tr></table>

# Note

Please note that if you receive a Time Limit Exceeded verdict, it is possible that your query is invalid or the number of queries exceeds the limit.

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


static long long queries = 0;
static long long query_limit = 6666;
static const long long HARD_CAP = 200000;


static int n;
static vector<int> hidden_p;


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

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

    
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    
    
    n = inf.readInt(1, 1000, "n");
    hidden_p.resize(n);
    for (int i = 0; i < n; i++) {
        hidden_p[i] = inf.readInt(1, n, format("p[%d]", i + 1).c_str());
    }

    
    cout << n << endl;

    
    while (true) {
        string token;
        if (!(cin >> token)) {
            finish(_pe, "Unexpected EOF while reading query type");
        }

        
        bool is_query = (token == "0" || token == "?");
        bool is_guess = (token == "1" || token == "!");

        if (!is_query && !is_guess) {
            finish(_pe, format("Expected '0' or '1', found '%s'", token.c_str()));
        }

        if (is_query) {
            queries++;
            
            if (queries % 50 == 0) {
                log_metrics();
            }
            
            if (queries > HARD_CAP) {
                finish(_pe, "Hard query limit exceeded");
            }

            
            vector<int> q(n);
            for (int i = 0; i < n; i++) {
                if (!(cin >> q[i])) {
                    finish(_pe, "Unexpected EOF while reading query sequence");
                }
                
                if (q[i] < 1 || q[i] > n) {
                    finish(_pe, format("Query element %d out of range [1, %d]", q[i], n));
                }
            }

            
            int matches = 0;
            for (int i = 0; i < n; i++) {
                if (q[i] == hidden_p[i]) {
                    matches++;
                }
            }

            
            cout << matches << endl;

        } else {
            
            vector<int> g(n);
            for (int i = 0; i < n; i++) {
                if (!(cin >> g[i])) {
                    finish(_pe, "Unexpected EOF while reading guess sequence");
                }
                
                if (g[i] < 1 || g[i] > n) {
                    finish(_pe, format("Guess element %d out of range [1, %d]", g[i], n));
                }
            }

            
            if (g == hidden_p) {
                finish(_ok, format("Correct! Solved in %lld queries.", queries));
            } else {
                finish(_wa, "Wrong guess.");
            }
        }
    }

    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");
    
    
    
    int n = opt<int>("n", 0);

    
    if (n == 0) {
        
        
        long long seed_val = -1;
        try {
            seed_val = stoll(string(argv[1]));
        } catch (...) {
            seed_val = -1;
        }

        
        if (seed_val == 1) n = 1;          
        else if (seed_val == 2) n = 1000;  
        else if (seed_val == 3) n = 2;     
        else if (seed_val == 4) n = 3;
        else if (seed_val == 5) n = 10;
        else {
            
            
            int t = rnd.next(1, 100);
            if (t <= 5) n = rnd.next(1, 10);          
            else if (t <= 15) n = rnd.next(11, 100);  
            else n = rnd.next(900, 1000);             
        }
    }

    
    cout << n << endl;

    if (mode == "non") {
        
        
        
        vector<int> p;
        int type = rnd.next(1, 100);

        
        
        if (n > 1 && type <= 20) {
            p.resize(n);
            iota(p.begin(), p.end(), 1); 

            if (type <= 5) {
                
            } else if (type <= 10) {
                
                reverse(p.begin(), p.end());
            } else if (type <= 15) {
                
                int shift = rnd.next(1, n - 1);
                rotate(p.begin(), p.begin() + shift, p.end());
            } else {
                
                int i = rnd.next(0, n - 1);
                int j = rnd.next(0, n - 1);
                while (i == j) j = rnd.next(0, n - 1);
                swap(p[i], p[j]);
            }
        } else {
            
            p = rnd.perm(n, 1);
        }

        
        println(p);
    } 
    else {
        
        
    }

    return 0;
}