Problem: cf1514_e
Difficulty: hard
Categories: graph, data structures, search
Time limit: 1000 ms, memory limit: 256 MB

This is an interactive problem.

Baby Ehab loves crawling around his apartment. It has $n$ rooms numbered from $0$ to $n-1$. For every pair of rooms, $a$ and $b$, there's either a direct passage from room $a$ to room $b$, or from room $b$ to room $a$, but never both.

Baby Ehab wants to go play with Baby Badawy. He wants to know if he could get to him. However, he doesn't know anything about his apartment except the number of rooms. He can ask the baby sitter two types of questions:

* is the passage between room $a$ and room $b$ directed from $a$ to $b$ or the other way around?
* does room $x$ have a passage towards any of the rooms $s_1$, $s_2$, ..., $s_k$?

He can ask at most $9n$ queries of the first type and at most $2n$ queries of the second type.

After asking some questions, he wants to know for every pair of rooms $a$ and $b$ whether there's a path from $a$ to $b$ or not. A path from $a$ to $b$ is a sequence of passages that starts from room $a$ and ends at room $b$.

Input

The first line contains an integer $t$ ($1 \le t \le 30$) — the number of test cases you need to solve.

Then each test case starts with an integer $n$ ($4 \le n \le 100$) — the number of rooms.

The sum of $n$ across the test cases doesn't exceed $500$.

Output

To print the answer for a test case, print a line containing "3", followed by $n$ lines, each containing a binary string of length $n$. The $j$-th character of the $i$-th string should be $1$ if there's a path from room $i$ to room $j$, and $0$ if there isn't. The $i$-th character of the $i$-th string should be $1$ for each valid $i$.

After printing the answer, we will respond with a single integer. If it's $1$, you printed a correct answer and should keep solving the test cases (or exit if it is the last one). If it's $-1$, you printed a wrong answer and should terminate to get Wrong answer verdict. Otherwise, you can get an arbitrary verdict because your solution will continue to read from a closed stream.

Interaction

To ask a question of the first type, use the format:

* $1$ $a$ $b$ ($0 \le a,b \le n-1$, $a \neq b$).
* we will answer with $1$ if the passage is from $a$ to $b$, and $0$ if it is from $b$ to $a$.
* you can ask at most $9n$ questions of this type in each test case.

To ask a question of the second type, use the format:

* $2$ $x$ $k$ $s_1$ $s_2$ ... $s_k$ ($0 \le x,s_i \le n-1$, $0 \le k < n$, $x \neq s_i$, elements of $s$ are pairwise distinct).
* we will answer with $1$ if there's a passage from $x$ to any of the rooms in $s$, and $0$ otherwise.
* you can ask at most $2n$ questions of this type in each test case.

If we answer with $-1$ instead of a valid answer, that means you exceeded the number of queries or made an invalid query. Exit immediately after receiving $-1$ and you will see Wrong answer verdict. Otherwise, you can get an arbitrary verdict because your solution will continue to read from a closed stream.

After printing a query, do not forget to output 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 the documentation for other languages.

Example

Input

```
1
4

0

0

1

1

1
```

Output

```
2 3 3 0 1 2

1 0 1

1 0 2

2 2 1 1

3
1111
1111
1111
0001
```

Note

In the given example:

![](https://espresso.codeforces.com/3594da6b18be97353606ae5c24af5f1a3967d44d.png)

The first query asks whether there's a passage from room $3$ to any of the other rooms.

The second query asks about the direction of the passage between rooms $0$ and $1$.

After a couple other queries, we concluded that you can go from any room to any other room except if you start at room $3$, and you can't get out of this room, so we printed the matrix:

```
1111  
1111  
1111  
0001
```

The interactor answered with $1$, telling us the answer is correct.

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

static bool readLL(long long& x) {
    return (cin >> x) ? true : false;
}

static void sendToContestant(long long x) {
    cout << x << "\n";
    cout.flush();
}

static void sendMinusOneAndPE(const string& msg) {
    sendToContestant(-1);
    finish(_pe, msg);
}

static void sendMinusOneAndWA(const string& msg) {
    sendToContestant(-1);
    finish(_wa, msg);
}

static uint64_t fnv1a64(const string& s) {
    uint64_t h = 14695981039346656037ULL;
    for (unsigned char c : s) {
        h ^= (uint64_t)c;
        h *= 1099511628211ULL;
    }
    return h;
}

static uint64_t splitmix64(uint64_t x) {
    x += 0x9e3779b97f4a7c15ULL;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;
    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;
    return x ^ (x >> 31);
}

static vector<string> generateTournament(int n, uint64_t seed) {
    vector<string> g(n, string(n, '0'));

    for (int i = 0; i < n; i++) {
        g[i][i] = '0';
        for (int j = i + 1; j < n; j++) {
            uint64_t h = splitmix64(seed ^ (uint64_t)(i + 1) * 0x9e3779b97f4a7c15ULL ^ (uint64_t)(j + 1));
            bool dir = (h & 1ULL);
            g[i][j] = dir ? '1' : '0';
            g[j][i] = dir ? '0' : '1';
        }
    }

    
    vector<int> p(n);
    iota(p.begin(), p.end(), 0);
    for (int i = n - 1; i >= 1; --i) {
        seed = splitmix64(seed);
        int j = (int)(seed % (uint64_t)(i + 1));
        swap(p[i], p[j]);
    }
    for (int i = 0; i < n; i++) {
        int u = p[i];
        int v = p[(i + 1) % n];
        g[u][v] = '1';
        g[v][u] = '0';
    }

    return g;
}

static const int MAXN = 105;

struct CaseData {
    int n;
    vector<string> g;           
    vector<bitset<MAXN>> reach; 
};

static vector<bitset<MAXN>> computeReach(int n, const vector<string>& g) {
    vector<bitset<MAXN>> reach(n);
    for (int i = 0; i < n; i++) {
        reach[i].reset();
        reach[i].set(i);
        for (int j = 0; j < n; j++) {
            if (i != j && g[i][j] == '1') reach[i].set(j);
        }
    }
    for (int k = 0; k < n; k++) {
        for (int i = 0; i < n; i++) {
            if (reach[i].test(k)) reach[i] |= reach[k];
        }
    }
    return reach;
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t = inf.readInt(1, 30, "t");
    vector<CaseData> cases;
    cases.reserve(t);

    long long sumN = 0;
    uint64_t seed = fnv1a64((argc >= 2) ? string(argv[1]) : string("cf1514E"));

    for (int tc = 0; tc < t; tc++) {
        int n = inf.readInt(4, 100, "n");
        sumN += n;
        if (sumN > 500) finish(_fail, "Hidden input: sum of n exceeds 500");

        vector<string> g;
        if (inf.seekEof()) {
            
            seed = splitmix64(seed ^ (uint64_t)n);
            g = generateTournament(n, seed);
        } else {
            
            g.assign(n, "");
            for (int i = 0; i < n; i++) {
                string s = inf.readToken();
                if ((int)s.size() != n) finish(_fail, "Hidden input: row length != n");
                for (int j = 0; j < n; j++) {
                    if (s[j] != '0' && s[j] != '1') finish(_fail, "Hidden input: non-binary char");
                }
                g[i] = std::move(s);
            }
        }

        
        for (int i = 0; i < n; i++) {
            if (g[i][i] != '0') g[i][i] = '0';
            for (int j = i + 1; j < n; j++) {
                char a = g[i][j], b = g[j][i];
                if (!((a == '0' && b == '1') || (a == '1' && b == '0'))) {
                    finish(_fail, "Hidden input: not a tournament (pair not complementary)");
                }
            }
        }

        CaseData cd;
        cd.n = n;
        cd.g = std::move(g);
        cd.reach = computeReach(n, cd.g);
        cases.push_back(std::move(cd));

        query_limit += 11LL * n; 
    }

    const long long hard_cap = max(200000LL, 10LL * max(1LL, query_limit));

    
    log_metrics();

    
    cout << t << "\n";
    cout.flush();

    for (int tc = 0; tc < t; tc++) {
        const int n = cases[tc].n;
        const auto& g = cases[tc].g;
        const auto& reach = cases[tc].reach;

        cout << n << "\n";
        cout.flush();

        long long q1 = 0, q2 = 0;
        while (true) {
            long long cmd;
            if (!readLL(cmd)) finish(_pe, "Unexpected EOF while waiting for command");

            if (cmd == 1) {
                long long a_ll, b_ll;
                if (!readLL(a_ll) || !readLL(b_ll)) finish(_pe, "EOF while reading query type 1");
                if (a_ll < 0 || a_ll >= n || b_ll < 0 || b_ll >= n) sendMinusOneAndPE("Type 1: index out of range");
                if (a_ll == b_ll) sendMinusOneAndPE("Type 1: a == b");
                int a = (int)a_ll, b = (int)b_ll;

                q1++;
                queries++;
                if (queries > hard_cap) sendMinusOneAndPE("Hard cap exceeded");
                if (q1 > 9LL * n) sendMinusOneAndPE("Type 1: query limit exceeded");

                int ans = (g[a][b] == '1') ? 1 : 0;
                sendToContestant(ans);
            } else if (cmd == 2) {
                long long x_ll, k_ll;
                if (!readLL(x_ll) || !readLL(k_ll)) finish(_pe, "EOF while reading query type 2 header");
                if (x_ll < 0 || x_ll >= n) sendMinusOneAndPE("Type 2: x out of range");
                if (k_ll < 0 || k_ll >= n) sendMinusOneAndPE("Type 2: k out of range");
                int x = (int)x_ll;
                int k = (int)k_ll;

                vector<int> s;
                s.reserve(k);
                vector<char> seen(n, 0);
                for (int i = 0; i < k; i++) {
                    long long si_ll;
                    if (!readLL(si_ll)) finish(_pe, "EOF while reading query type 2 set");
                    if (si_ll < 0 || si_ll >= n) sendMinusOneAndPE("Type 2: s_i out of range");
                    int si = (int)si_ll;
                    if (si == x) sendMinusOneAndPE("Type 2: s_i == x");
                    if (seen[si]) sendMinusOneAndPE("Type 2: duplicate s_i");
                    seen[si] = 1;
                    s.push_back(si);
                }

                q2++;
                queries++;
                if (queries > hard_cap) sendMinusOneAndPE("Hard cap exceeded");
                if (q2 > 2LL * n) sendMinusOneAndPE("Type 2: query limit exceeded");

                int ans = 0;
                for (int si : s) {
                    if (g[x][si] == '1') {
                        ans = 1;
                        break;
                    }
                }
                sendToContestant(ans);
            } else if (cmd == 3) {
                vector<string> out(n);
                for (int i = 0; i < n; i++) {
                    string row;
                    if (!(cin >> row)) finish(_pe, "EOF while reading final answer matrix");
                    if ((int)row.size() != n) sendMinusOneAndPE("Final answer: row length != n");
                    for (int j = 0; j < n; j++) {
                        if (row[j] != '0' && row[j] != '1') sendMinusOneAndPE("Final answer: non-binary character");
                    }
                    out[i] = std::move(row);
                }

                for (int i = 0; i < n; i++) {
                    if (out[i][i] != '1') sendMinusOneAndWA("Final answer: diagonal must be 1");
                    for (int j = 0; j < n; j++) {
                        bool got = (out[i][j] == '1');
                        bool exp = reach[i].test(j);
                        if (got != exp) sendMinusOneAndWA("Final answer: reachability mismatch");
                    }
                }

                sendToContestant(1);
                break;
            } else {
                sendMinusOneAndPE("Unknown command (expected 1/2/3)");
            }
        }
    }

    finish(_ok, "OK");
}



Adaptive interactor (C++):

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

static void setEdge(vector<string>& g, int a, int b, int dirAB) {
    if (a == b) return;
    if (dirAB) {
        g[a][b] = '1';
        g[b][a] = '0';
    } else {
        g[a][b] = '0';
        g[b][a] = '1';
    }
}

static vector<int> rndPerm(int n) {
    vector<int> p(n);
    iota(p.begin(), p.end(), 0);
    for (int i = 0; i < n; i++) {
        int j = rnd.next(i, n - 1);
        swap(p[i], p[j]);
    }
    return p;
}

static vector<string> buildTransitive(int n) {
    vector<string> g(n, string(n, '0'));
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++)
            setEdge(g, i, j, 1);
    return g;
}

static vector<string> buildCirculant(int n) {
    vector<string> g(n, string(n, '0'));
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            int d = j - i;
            int rev = n - d;
            if (d < rev) setEdge(g, i, j, 1);
            else if (d > rev) setEdge(g, i, j, 0);
            else setEdge(g, i, j, (i % 2 == 0) ? 1 : 0); 
        }
    }
    return g;
}

static vector<string> buildRandomStrong(int n) {
    vector<string> g(n, string(n, '0'));
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            int dir = rnd.next(0, 1);
            setEdge(g, i, j, dir);
        }
    }
    
    vector<int> p = rndPerm(n);
    for (int i = 0; i < n; i++) {
        int u = p[i];
        int v = p[(i + 1) % n];
        setEdge(g, u, v, 1);
    }
    return g;
}

static vector<string> buildBlocksChain(int n, int minSz, int maxSz, bool allowSmallBlocks) {
    vector<string> g(n, string(n, '0'));
    vector<int> order = rndPerm(n);

    vector<pair<int,int>> blocks; 
    int pos = 0;
    while (pos < n) {
        int rem = n - pos;
        int sz;
        if (rem <= 2) {
            sz = rem; 
        } else {
            int lo = minSz, hi = maxSz;
            if (allowSmallBlocks) lo = 1;
            lo = max(lo, 1);
            hi = max(hi, lo);
            sz = rnd.next(lo, min(hi, rem));
            if (!allowSmallBlocks && sz < 3) sz = 3;
            if (sz > rem) sz = rem;
            if (!allowSmallBlocks && rem < 3) sz = rem;
            if (!allowSmallBlocks && sz == 2) sz = 3 <= rem ? 3 : rem;
        }
        blocks.push_back({pos, pos + sz});
        pos += sz;
    }

    
    for (int bi = 0; bi < (int)blocks.size(); bi++) {
        for (int bj = bi + 1; bj < (int)blocks.size(); bj++) {
            for (int ii = blocks[bi].first; ii < blocks[bi].second; ii++) {
                int u = order[ii];
                for (int jj = blocks[bj].first; jj < blocks[bj].second; jj++) {
                    int v = order[jj];
                    setEdge(g, u, v, 1);
                }
            }
        }
    }

    
    for (auto [l, r] : blocks) {
        int sz = r - l;
        vector<int> verts;
        verts.reserve(sz);
        for (int i = l; i < r; i++) verts.push_back(order[i]);

        
        for (int i = 0; i < sz; i++) {
            int j = rnd.next(i, sz - 1);
            swap(verts[i], verts[j]);
        }

        
        for (int i = 0; i < sz; i++) {
            for (int j = i + 1; j < sz; j++) {
                int dir = rnd.next(0, 1);
                setEdge(g, verts[i], verts[j], dir);
            }
        }

        
        if (sz >= 3) {
            for (int i = 0; i < sz; i++) {
                int u = verts[i];
                int v = verts[(i + 1) % sz];
                setEdge(g, u, v, 1);
            }
        }
    }

    return g;
}

static vector<string> buildWindowMostlyTransitive(int n, int w) {
    vector<string> g(n, string(n, '0'));
    vector<int> ord = rndPerm(n);

    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            int u = ord[i], v = ord[j];
            int dir;
            if (j - i <= w) dir = rnd.next(0, 1);
            else dir = 1; 
            setEdge(g, u, v, dir);
        }
    }

    
    int flips = max(1, n / 3);
    for (int it = 0; it < flips; it++) {
        int i = rnd.next(0, n - 1);
        int j = rnd.next(0, n - 1);
        if (i == j) { it--; continue; }
        if (abs(i - j) <= w) { it--; continue; }
        int u = ord[min(i, j)];
        int v = ord[max(i, j)];
        
        setEdge(g, u, v, 0);
    }

    
    vector<int> p = rndPerm(n);
    for (int i = 0; i < n; i++) {
        int u = p[i], v = p[(i + 1) % n];
        setEdge(g, u, v, 1);
    }
    return g;
}

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

    string mode = opt<string>("mode", "non"); 
    int nOpt = opt<int>("n", -1);
    string style = opt<string>("style", "auto"); 

    long long seedVal = 0;
    if (argc >= 2) {
        
        seedVal = atoll(argv[1]);
    }

    int n;
    if (nOpt != -1) n = nOpt;
    else if (seedVal == 1) n = 4;
    else if (seedVal == 2) n = 100;
    else if (seedVal == 3) n = 100;
    else n = rnd.next(80, 100);

    ensuref(4 <= n && n <= 100, "n out of range: %d", n);

    
    if (mode == "adp") {
        cout << 1 << "\n";
        cout << n << "\n";
        return 0;
    }

    vector<string> g;

    if (style != "auto") {
        if (style == "transitive") g = buildTransitive(n);
        else if (style == "circulant") g = buildCirculant(n);
        else if (style == "random") g = buildRandomStrong(n);
        else if (style == "blocks") {
            int minSz = opt<int>("minBlock", 3);
            int maxSz = opt<int>("maxBlock", 7);
            bool allowSmall = opt<int>("allowSmall", 0) != 0;
            g = buildBlocksChain(n, minSz, maxSz, allowSmall);
        } else if (style == "window") {
            int w = opt<int>("w", max(2, n / 10));
            g = buildWindowMostlyTransitive(n, w);
        } else {
            quitf(_fail, "unknown --style: %s", style.c_str());
        }
    } else {
        if (seedVal == 1) {
            g = buildTransitive(n); 
        } else if (seedVal == 2) {
            g = buildCirculant(n); 
        } else if (seedVal == 3) {
            
            
            g = buildBlocksChain(n, 3, 6, false);
        } else {
            int pick = rnd.next(1, 100);
            if (pick <= 45) {
                g = buildBlocksChain(n, 3, 8, true);
            } else if (pick <= 80) {
                g = buildRandomStrong(n);
            } else {
                int w = rnd.next(2, max(2, n / 8));
                g = buildWindowMostlyTransitive(n, w);
            }
        }
    }

    
    cout << 1 << "\n";
    cout << n << "\n";
    for (int i = 0; i < n; i++) {
        ensure((int)g[i].size() == n);
        g[i][i] = '0';
        cout << g[i] << "\n";
    }
    return 0;
}