Problem: icpc2025_asia_pacific_championship_e
Difficulty: hard
Categories: graph
Time limit: 2000 ms, memory limit: 256 MB

The minus operator on binary values $a$ and $b$ is defined by $( a - b ) = 1$ if $a = 1$ and $b = 0$ ; otherwise, $( a - b ) = 0$ . Also, the syntax of an expression is defined as follows. Here, $_ \textrm { x }$ , parentheses, and the minus are terminal symbols, and $E$ is the start symbol.

$$
E : = \textbf { x } \mid \mathbf { \Omega } ( E - E )
$$

The judge program possesses an expression adhering to $E$ . The expression is hidden from you. At the start, you are only provided with the number of terminal symbols $_ \textrm { x }$ in the expression, denoted by $n$ .

Your task is to guess the expression by making a limited number of queries.

In a single query, you specify a binary string $S$ of length $n$ . The judge program then temporarily replaces each occurrence of the $i$ -th terminal symbol $_ \textrm { x }$ from the left with $S _ { i }$ , for $i = 1 , \ldots , n$ , and evaluates the replaced expression based on the definition of the minus operator. After that, the judge program returns the evaluated value to you, which is either 0 or 1.

# Interaction

The first line of input contains an integer $n$ $3 \leq n \leq 2 0 0$ ). After reading the integer, your program can start making queries. For each query, your program should write a line of the form “query $S ^ { \ast }$ . Here, $S$ is a binary string of length $n$ . Each character of $S$ must be either 0 or 1. In response, an input line containing the evaluated value becomes available.

Your program can make up to 500 queries. If your program makes more than 500 queries, it will be judged as “Wrong Answer.”

When your program identifies the expression that the judge program possesses, it should write a line of the form “answer $T ^  \ast \}$ , where $T$ is the expression. After that, the interaction stops and your program should terminate.

Under the constraints above, it can be shown that the expression can be uniquely identified.

Notes on interactive judging:

• The evaluation is non-adversarial, meaning that the expression is chosen in advance rather than in response to your queries.   
• Do not forget to flush output buffers after writing. See the “Judging Details” document for details.   
• You are provided with a command-line tool for local testing, together with input files corresponding to the sample interactions. You can download these files from DOMjudge. The tool has comments at the top to explain its use.

# The 2025 ICPC Asia Pacific Championship

Hosted by the National University of Singapore

# Sample Interaction #1

Explanation for the sample interaction #1

When $n = 3$ , there are only two possible expressions: $( \mathbf { \partial } ( \mathbf { \partial } \mathbf { x } - \mathbf { x } ) - \mathbf { x } )$ or $\left( \mathbf { X } ^ { - } \left( \mathbf { X } ^ { - } \mathbf { X } \right) \ \right)$ . For a query $s = 1 1 1$ , the evaluated values for these expressions are,

In this example, the judge program returns 0, indicating that the first expression is the correct one.

![](images/c57d081e93e955b0624e5137ab7ccd5cea9c764332415d30afb1aa8a14d19ca3.jpg)

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

using namespace std;


static long long queries = 0;

static long long query_limit = 500; 
static const long long hard_cap = 20000; 




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


struct Node {
    bool is_leaf;
    int leaf_idx; 
    Node *left = nullptr;
    Node *right = nullptr;

    Node(int idx) : is_leaf(true), leaf_idx(idx) {}
    Node(Node* l, Node* r) : is_leaf(false), leaf_idx(-1), left(l), right(r) {}
    
    ~Node() {
        if (left) delete left;
        if (right) delete right;
    }
};

string hidden_expr_str;
int parse_pos = 0;
int leaf_counter = 0;



Node* parse_expression() {
    if (parse_pos >= (int)hidden_expr_str.length()) {
        quitf(_fail, "Unexpected end of hidden expression during parsing");
    }

    if (hidden_expr_str[parse_pos] == 'x') {
        parse_pos++;
        return new Node(leaf_counter++);
    } else if (hidden_expr_str[parse_pos] == '(') {
        parse_pos++; 
        Node* left = parse_expression();
        
        if (parse_pos >= (int)hidden_expr_str.length() || hidden_expr_str[parse_pos] != '-') {
            quitf(_fail, "Invalid expression format: expected '-' at pos %d", parse_pos);
        }
        parse_pos++; 
        
        Node* right = parse_expression();
        
        if (parse_pos >= (int)hidden_expr_str.length() || hidden_expr_str[parse_pos] != ')') {
            quitf(_fail, "Invalid expression format: expected ')' at pos %d", parse_pos);
        }
        parse_pos++; 
        
        return new Node(left, right);
    } else {
        quitf(_fail, "Invalid character '%c' in expression at pos %d", hidden_expr_str[parse_pos], parse_pos);
        return nullptr;
    }
}


int evaluate(Node* node, const string& S) {
    if (node->is_leaf) {
        
        return (S[node->leaf_idx] == '1' ? 1 : 0);
    } else {
        int l = evaluate(node->left, S);
        int r = evaluate(node->right, S);
        if (l == 1 && r == 0) return 1;
        else return 0;
    }
}


string clean_string(const string& s) {
    string res;
    for (char c : s) {
        if (!isspace((unsigned char)c)) res += c;
    }
    return res;
}

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

    
    int n = inf.readInt();
    hidden_expr_str = inf.readToken(); 
    
    
    leaf_counter = 0;
    parse_pos = 0;
    Node* root = parse_expression();
    
    
    if (leaf_counter != n) {
        quitf(_fail, "Parsed leaf count (%d) does not match N (%d) in hidden input", leaf_counter, n);
    }
    if (parse_pos != (int)hidden_expr_str.length()) {
        quitf(_fail, "Extra characters found after parsing hidden expression");
    }

    
    cout << n << endl;
    
    
    while (true) {
        
        if (queries > hard_cap) {
            finish(_pe, "Hard query limit exceeded (anti-spam)");
        }

        string token;
        if (!(cin >> token)) {
            
            finish(_wa, "Unexpected EOF (solution terminated without providing answer)");
        }

        bool is_query = false;
        bool is_answer = false;
        string payload = "";

        
        
        
        
        
        if (token == "query" || token == "?") {
            is_query = true;
            if (!(cin >> payload)) finish(_wa, "EOF after query command");
        } 
        else if (token == "answer" || token == "!") {
            is_answer = true;
            string line;
            getline(cin, line);
            payload = line;
        } 
        else if (token.size() > 1 && token[0] == '?') {
            is_query = true;
            payload = token.substr(1);
        } 
        else if (token.size() > 1 && token[0] == '!') {
            is_answer = true;
            string line;
            getline(cin, line);
            payload = token.substr(1) + line;
        } 
        else if (token.find("answer") == 0) { 
            is_answer = true;
            string line;
            getline(cin, line);
            payload = token.substr(6) + line;
        } 
        else {
            finish(_wa, "Invalid command token: " + token);
        }

        if (is_query) {
            queries++;
            
            if (queries % 10 == 0) log_metrics();

            if (queries > query_limit) {
                finish(_wa, "Query limit exceeded (> " + to_string(query_limit) + ")");
            }

            
            if ((int)payload.length() != n) {
                finish(_wa, "Query string length must be " + to_string(n) + ", got " + to_string(payload.length()));
            }
            for (char c : payload) {
                if (c != '0' && c != '1') {
                    finish(_wa, "Query string must contain only '0' and '1'");
                }
            }

            
            int res = evaluate(root, payload);
            cout << res << endl; 
            
        } else if (is_answer) {
            
            string user_clean = clean_string(payload);
            string hidden_clean = clean_string(hidden_expr_str);

            if (user_clean == hidden_clean) {
                finish(_ok, "Correct expression identified");
            } else {
                finish(_wa, "Incorrect expression. Expected: " + hidden_clean + ", Got: " + user_clean);
            }
        }
    }

    
    delete root;
    return 0;
}


Adaptive interactor (C++):

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

using namespace std;


double cat[205];
bool cat_computed = false;


void precompute_cat() {
    if (cat_computed) return;
    cat[0] = 1.0;
    
    
    
    
    
    for (int i = 1; i <= 200; ++i) {
        cat[i] = 0;
        for (int j = 0; j < i; ++j) {
            cat[i] += cat[j] * cat[i - 1 - j];
        }
    }
    cat_computed = true;
}


string gen_catalan(int n) {
    if (n == 1) return "x";
    precompute_cat();
    
    
    double total_ways = cat[n - 1];
    double r = rnd.next() * total_ways;
    
    int k = -1;
    double current_sum = 0;
    
    
    
    
    for (int i = 1; i < n; ++i) {
        double ways = cat[i - 1] * cat[n - i - 1];
        if (current_sum + ways >= r) {
            k = i;
            break;
        }
        current_sum += ways;
    }
    if (k == -1) k = n - 1; 
    
    return "(" + gen_catalan(k) + "-" + gen_catalan(n - k) + ")";
}



string gen_bst(int n) {
    if (n == 1) return "x";
    int k = rnd.next(1, n - 1);
    return "(" + gen_bst(k) + "-" + gen_bst(n - k) + ")";
}




string gen_skewed(int n, int dir) {
    if (n == 1) return "x";
    int k;
    if (dir == 0) k = n - 1; 
    else k = 1;              
    return "(" + gen_skewed(k, dir) + "-" + gen_skewed(n - k, dir) + ")";
}


string gen_zigzag(int n, bool left) {
    if (n == 1) return "x";
    int k = left ? (n - 1) : 1;
    return "(" + gen_zigzag(k, !left) + "-" + gen_zigzag(n - k, !left) + ")";
}

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);
    
    string mode = opt<string>("mode", "non");
    int n_arg = opt<int>("n", 0);
    
    int n = n_arg;
    int seed_idx = atoi(argv[1]);
    
    
    if (n == 0) {
        if (seed_idx == 1) n = 3;           
        else if (seed_idx == 2) n = 200;    
        else if (seed_idx == 3) n = 199;    
        else if (seed_idx == 4) n = 10;
        else if (seed_idx == 5) n = 50;
        else if (seed_idx == 6) n = 100;
        else n = rnd.next(3, 200);          
    }
    
    
    string expr;
    
    if (seed_idx == 1) {
        
        expr = gen_catalan(n);
    } else if (seed_idx == 2) {
        
        expr = gen_skewed(n, 1);
    } else if (seed_idx == 3) {
        
        expr = gen_skewed(n, 0);
    } else if (seed_idx == 4) {
        
        expr = gen_zigzag(n, true);
    } else if (seed_idx == 5) {
        
        expr = gen_bst(n);
    } else if (seed_idx == 6) {
        
        expr = gen_catalan(n);
    } else {
        
        int type = rnd.next(100);
        if (type < 40) expr = gen_catalan(n);          
        else if (type < 70) expr = gen_bst(n);         
        else if (type < 85) expr = gen_skewed(n, 0);   
        else expr = gen_skewed(n, 1);                  
    }

    if (mode == "adp") {
        
        println(n);
    } else {
        
        println(n);
        println(expr);
    }
    
    return 0;
}