Problem: cf1977_e
Difficulty: easy
Categories: graph, greedy
Time limit: 3000 ms, memory limit: 256 MB

This is an interactive problem.

You are given an integer $n$.

The jury has hidden from you a directed graph with $n$ vertices (numbered from $1$ to $n$) and some number of edges. You additionally know that:

* The graph only contains edges of the form $i \leftarrow j$, where $1 \le i < j \le n$.
* For any three vertices $1 \le i < j < k \le n$, at least one of the following holds$^\dagger$:
  + Vertex $i$ is reachable from vertex $j$, or
  + Vertex $i$ is reachable from vertex $k$, or
  + Vertex $j$ is reachable from vertex $k$.

You want to color each vertex in either black or white such that for any two vertices $i$ and $j$ ($1 \le i < j \le n$) of the same color, vertex $i$ is reachable from vertex $j$.

To do that, you can ask queries of the following type:

*? i j — is vertex $i$ reachable from vertex $j$ ($1 \le i < j \le n$)?

Find any valid vertex coloring of the hidden graph in at most $2 \cdot n$ queries. It can be proven that such a coloring always exists.

Note that the grader is not adaptive: the graph is fixed before any queries are made.

$^\dagger$ Vertex $a$ is reachable from vertex $b$ if there exists a path from vertex $b$ to vertex $a$ in the graph.

Input

Each test contains multiple test cases. The first line of input contains a single integer $t$ ($1 \le t \le 1000$) — the number of test cases. The description of the test cases follows.

The only line of each test case contains a single integer $n$ ($3 \le n \le 100$) — the number of vertices in the hidden graph.

It is guaranteed that the sum of $n$ over all test cases does not exceed $1000$.

Interaction

The interaction for each test case begins by reading the integer $n$.

To make a query, output "? i j" without quotes ($1 \le i < j \le n$). If vertex $i$ is reachable from vertex $j$, you will get YES as an answer. Otherwise, you will get NO as an answer.

If you receive the integer $-1$ instead of an answer or a valid value of $n$, it means your program has made an invalid query, has exceeded the limit of queries, or has given an incorrect answer on the previous test case. Your program must terminate immediately to receive a Wrong Answer verdict. Otherwise, you can get an arbitrary verdict because your solution will continue to read from a closed stream.

When you are ready to give the final answer, output "! $c_1 \ c_2 \ \ldots \ c_n$" without quotes — the colors of the vertices, where $c_i = 0$ if the vertex is black, and $c_i = 1$ if the vertex is white. After solving all test cases, your program should be terminated immediately.

After printing a query, do not forget to output an end of line and flush the output. Otherwise, you will get Idleness limit exceeded. To do this, use:

* fflush(stdout) or cout.flush() in C++;
* System.out.flush() in Java;
* flush(output) in Pascal;
* stdout.flush() in Python;
* see documentation for other languages.

Example

Input

```
2
4

YES

YES

YES

NO

NO

NO

5
```

Output

```? 1 2? 2 3? 1 3? 1 4? 2 4? 3 4! 0 0 0 1! 1 1 0 1 0
```

Note

The hidden graph in the first test case:![](https://espresso.codeforces.com/2c76b6097ab80b5e09fcef2a83a9df40cd211c80.png) 

The hidden graph in the second test case:![](https://espresso.codeforces.com/c20c9e6f58a290ede775f40980c1691398ae8cb2.png) 

The interaction happens as follows:

|  |  |  |
| --- | --- | --- |
| Solution | Jury | Explanation |
|  | 2 | There are $2$ test cases. |
|  | 4 | In the first test case, the graph has $4$ vertices. |
|? 1 2 | YES | The solution asks if vertex $1$ is reachable from vertex $2$, and the jury answers YES. |
|? 2 3 | YES | The solution asks if vertex $2$ is reachable from vertex $3$, and the jury answers YES. |
|? 1 3 | YES | The solution asks if vertex $1$ is reachable from vertex $3$, and the jury answers YES. |
|? 1 4 | NO | The solution asks if vertex $1$ is reachable from vertex $4$, and the jury answers NO. |
|? 2 4 | NO | The solution asks if vertex $2$ is reachable from vertex $4$, and the jury answers NO. |
|? 3 4 | NO | The solution asks if vertex $3$ is reachable from vertex $4$, and the jury answers NO. |
|! 0 0 0 1 |  | The solution has somehow determined a valid coloring and outputs it. Since the output is correct, the jury continues to the next test case. |
|  | 5 | In the second test case, the graph has $5$ vertices. |
|! 1 1 0 1 0 |  | The solution has somehow determined a valid coloring, and outputs it. Since the output is correct and there are no more test cases, the jury and the solution exit. |

Note that the line breaks in the example input and output are for the sake of clarity, and do not occur in the real interaction.

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

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

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

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

struct TestCase {
    int n = 0;
    vector<vector<unsigned char>> reach; 
};

static bool readTokenFromContestant(string& tok) {
    return (cin >> tok) ? true : false;
}

static bool parseNonNegInt(const string& s, int& out) {
    if (s.empty()) return false;
    long long v = 0;
    for (char c : s) {
        if (c < '0' || c > '9') return false;
        v = v * 10 + (c - '0');
        if (v > INT_MAX) return false;
    }
    out = (int)v;
    return true;
}

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

    int t = 0;
    try {
        t = inf.readInt(1, 1000, "t");
    } catch (...) {
        query_limit = 0;
        log_metrics();
        finish(_pe, "failed to read t from inf");
    }

    vector<TestCase> tests;
    tests.reserve(t);

    long long sum_n = 0;
    for (int tc = 0; tc < t; tc++) {
        TestCase cs;
        try {
            cs.n = inf.readInt(3, 100, "n");
        } catch (...) {
            query_limit = 0;
            log_metrics();
            finish(_pe, "failed to read n from inf");
        }
        sum_n += cs.n;
        cs.reach.assign(cs.n + 1, vector<unsigned char>(cs.n + 1, 0));

        for (int j = 2; j <= cs.n; j++) {
            string s;
            try {
                s = inf.readToken();
            } catch (...) {
                query_limit = 0;
                log_metrics();
                finish(_pe, "failed to read reachability row from inf");
            }
            if ((int)s.size() != j - 1) {
                query_limit = 0;
                log_metrics();
                finish(_pe, "invalid reachability row length in inf");
            }
            for (int i = 1; i < j; i++) {
                char c = s[i - 1];
                if (c != '0' && c != '1') {
                    query_limit = 0;
                    log_metrics();
                    finish(_pe, "invalid reachability character in inf");
                }
                cs.reach[i][j] = (unsigned char)(c == '1');
            }
        }

        tests.push_back(std::move(cs));
    }

    if (sum_n > 1000) {
        query_limit = 0;
        log_metrics();
        finish(_pe, "sum of n exceeds constraints");
    }

    query_limit = 2LL * sum_n;

    
    log_metrics();

    long long hard_cap = max(200000LL, 10LL * query_limit);
    if (hard_cap < 200000LL) hard_cap = 200000LL;

    cout << t << "\n" << flush;

    for (int tc = 0; tc < t; tc++) {
        const TestCase& cs = tests[tc];
        const int n = cs.n;

        cout << n << "\n" << flush;

        while (true) {
            string cmd;
            if (!readTokenFromContestant(cmd)) {
                finish(_pe, "unexpected EOF from contestant");
            }

            if (cmd == "?") {
                string si, sj;
                if (!readTokenFromContestant(si) || !readTokenFromContestant(sj)) {
                    finish(_pe, "malformed query: missing i or j");
                }
                int i = 0, j = 0;
                if (!parseNonNegInt(si, i) || !parseNonNegInt(sj, j)) {
                    finish(_pe, "malformed query: i/j not integers");
                }
                if (!(1 <= i && i < j && j <= n)) {
                    finish(_pe, "invalid query indices");
                }

                queries++;
                if (queries > hard_cap) {
                    finish(_pe, "hard cap exceeded");
                }

                cout << (cs.reach[i][j] ? "YES" : "NO") << "\n" << flush;
            } else if (cmd == "!") {
                vector<int> color(n + 1, -1);
                for (int v = 1; v <= n; v++) {
                    string sc;
                    if (!readTokenFromContestant(sc)) {
                        finish(_pe, "malformed answer: missing colors");
                    }
                    int c = 0;
                    if (!parseNonNegInt(sc, c) || !(c == 0 || c == 1)) {
                        finish(_pe, "malformed answer: colors must be 0/1");
                    }
                    color[v] = c;
                }

                for (int i = 1; i <= n; i++) {
                    for (int j = i + 1; j <= n; j++) {
                        if (color[i] == color[j] && cs.reach[i][j] == 0) {
                            finish(_wa, "invalid coloring");
                        }
                    }
                }

                break; 
            } else {
                finish(_pe, "unexpected token from contestant");
            }
        }
    }

    finish(_ok, "ok");
}


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

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

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

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

struct TestCase {
    int n = 0;
    vector<vector<unsigned char>> reach; 
};

static bool readTokenFromContestant(string& tok) {
    return (cin >> tok) ? true : false;
}

static bool parseNonNegInt(const string& s, int& out) {
    if (s.empty()) return false;
    long long v = 0;
    for (char c : s) {
        if (c < '0' || c > '9') return false;
        v = v * 10 + (c - '0');
        if (v > INT_MAX) return false;
    }
    out = (int)v;
    return true;
}

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

    int t = 0;
    try {
        t = inf.readInt(1, 1000, "t");
    } catch (...) {
        query_limit = 0;
        log_metrics();
        finish(_pe, "failed to read t from inf");
    }

    vector<TestCase> tests;
    tests.reserve(t);

    long long sum_n = 0;
    for (int tc = 0; tc < t; tc++) {
        TestCase cs;
        try {
            cs.n = inf.readInt(3, 100, "n");
        } catch (...) {
            query_limit = 0;
            log_metrics();
            finish(_pe, "failed to read n from inf");
        }
        sum_n += cs.n;
        cs.reach.assign(cs.n + 1, vector<unsigned char>(cs.n + 1, 0));

        for (int j = 2; j <= cs.n; j++) {
            string s;
            try {
                s = inf.readToken();
            } catch (...) {
                query_limit = 0;
                log_metrics();
                finish(_pe, "failed to read reachability row from inf");
            }
            if ((int)s.size() != j - 1) {
                query_limit = 0;
                log_metrics();
                finish(_pe, "invalid reachability row length in inf");
            }
            for (int i = 1; i < j; i++) {
                char c = s[i - 1];
                if (c != '0' && c != '1') {
                    query_limit = 0;
                    log_metrics();
                    finish(_pe, "invalid reachability character in inf");
                }
                cs.reach[i][j] = (unsigned char)(c == '1');
            }
        }

        tests.push_back(std::move(cs));
    }

    if (sum_n > 1000) {
        query_limit = 0;
        log_metrics();
        finish(_pe, "sum of n exceeds constraints");
    }

    query_limit = 2LL * sum_n;

    
    log_metrics();

    long long hard_cap = max(200000LL, 10LL * query_limit);
    if (hard_cap < 200000LL) hard_cap = 200000LL;

    cout << t << "\n" << flush;

    for (int tc = 0; tc < t; tc++) {
        const TestCase& cs = tests[tc];
        const int n = cs.n;

        cout << n << "\n" << flush;

        while (true) {
            string cmd;
            if (!readTokenFromContestant(cmd)) {
                finish(_pe, "unexpected EOF from contestant");
            }

            if (cmd == "?") {
                string si, sj;
                if (!readTokenFromContestant(si) || !readTokenFromContestant(sj)) {
                    finish(_pe, "malformed query: missing i or j");
                }
                int i = 0, j = 0;
                if (!parseNonNegInt(si, i) || !parseNonNegInt(sj, j)) {
                    finish(_pe, "malformed query: i/j not integers");
                }
                if (!(1 <= i && i < j && j <= n)) {
                    finish(_pe, "invalid query indices");
                }

                queries++;
                if (queries > hard_cap) {
                    finish(_pe, "hard cap exceeded");
                }

                cout << (cs.reach[i][j] ? "YES" : "NO") << "\n" << flush;
            } else if (cmd == "!") {
                vector<int> color(n + 1, -1);
                for (int v = 1; v <= n; v++) {
                    string sc;
                    if (!readTokenFromContestant(sc)) {
                        finish(_pe, "malformed answer: missing colors");
                    }
                    int c = 0;
                    if (!parseNonNegInt(sc, c) || !(c == 0 || c == 1)) {
                        finish(_pe, "malformed answer: colors must be 0/1");
                    }
                    color[v] = c;
                }

                for (int i = 1; i <= n; i++) {
                    for (int j = i + 1; j <= n; j++) {
                        if (color[i] == color[j] && cs.reach[i][j] == 0) {
                            finish(_wa, "invalid coloring");
                        }
                    }
                }

                break; 
            } else {
                finish(_pe, "unexpected token from contestant");
            }
        }
    }

    finish(_ok, "ok");
}


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

static vector<int> make_two_chain_labels(int n, int a0) {
    a0 = max(1, min(n - 1, a0));
    int a1 = n - a0;
    int rem0 = a0, rem1 = a1;
    int cur = rnd.next(0, 1);
    vector<int> lab;
    lab.reserve(n);
    while ((int)lab.size() < n) {
        if (cur == 0 && rem0 == 0) cur = 1;
        if (cur == 1 && rem1 == 0) cur = 0;
        int &rem = (cur == 0 ? rem0 : rem1);
        int maxRun = min(4, rem);
        int runLen = rnd.next(1, maxRun);
        for (int k = 0; k < runLen; k++) lab.push_back(cur);
        rem -= runLen;
        cur ^= 1;
    }
    return lab;
}

static vector<int> make_perm_from_two_chains(int n, const vector<int>& labels, bool layeredValues) {
    int a0 = 0;
    for (int x : labels) a0 += (x == 0);
    int a1 = n - a0;

    vector<int> values0, values1;
    values0.reserve(a0);
    values1.reserve(a1);

    if (layeredValues) {
        for (int v = n - a0 + 1; v <= n; v++) values0.push_back(v);
        for (int v = 1; v <= n - a0; v++) values1.push_back(v);
    } else {
        vector<int> all(n);
        iota(all.begin(), all.end(), 1);
        for (int i = n - 1; i >= 1; i--) {
            int j = rnd.next(0, i);
            swap(all[i], all[j]);
        }
        for (int i = 0; i < a0; i++) values0.push_back(all[i]);
        for (int i = a0; i < n; i++) values1.push_back(all[i]);
        sort(values0.begin(), values0.end());
        sort(values1.begin(), values1.end());
    }

    int p0 = 0, p1 = 0;
    vector<int> p(n);
    for (int i = 0; i < n; i++) {
        if (labels[i] == 0) p[i] = values0[p0++];
        else p[i] = values1[p1++];
    }
    return p;
}

static bool is_321_avoiding(const vector<int>& p) {
    int n = (int)p.size();
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) if (p[i] > p[j]) {
            for (int k = j + 1; k < n; k++) {
                if (p[j] > p[k]) return false;
            }
        }
    }
    return true;
}

static vector<int> pair_swap_perm(int n) {
    vector<int> p;
    p.reserve(n);
    for (int i = 1; i <= n; i += 2) {
        if (i + 1 <= n) {
            p.push_back(i + 1);
            p.push_back(i);
        } else {
            p.push_back(i);
        }
    }
    return p;
}

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

    string mode = opt<string>("mode", "non");
    long long seed = atoll(argv[1]);

    int n = opt<int>("n", -1);
    if (n == -1) {
        if (seed == 1) n = 3;
        else n = 100;
    }
    n = max(3, min(100, n));

    cout << 1 << "\n";
    cout << n << "\n";

    
    
    if (mode != "non" && mode != "adp") return 0;

    vector<int> p;
    if (seed == 1) {
        if (n == 3) p = {2, 1, 3};
        else p = pair_swap_perm(n);
    } else if (seed == 2) {
        p.resize(n);
        iota(p.begin(), p.end(), 1);
    } else if (seed == 3) {
        int k = n / 2;
        p.clear();
        for (int v = k + 1; v <= n; v++) p.push_back(v);
        for (int v = 1; v <= k; v++) p.push_back(v);
    } else {
        int a0 = n / 2 + rnd.next(-max(0, n / 10), max(0, n / 10));
        auto labels = make_two_chain_labels(n, a0);

        int variant = rnd.next(0, 2);
        if (variant == 0) {
            p = pair_swap_perm(n);
        } else if (variant == 1) {
            bool layered = true;
            p = make_perm_from_two_chains(n, labels, layered);
        } else {
            bool layered = (rnd.next(0, 1) == 1);
            p = make_perm_from_two_chains(n, labels, layered);
        }

        if (!is_321_avoiding(p)) {
            p = pair_swap_perm(n);
        }
    }

    for (int j = 2; j <= n; j++) {
        string s;
        s.reserve(j - 1);
        for (int i = 1; i < j; i++) {
            s.push_back((p[i - 1] < p[j - 1]) ? '1' : '0');
        }
        cout << s << "\n";
    }

    return 0;
}