This is an interactive problem.

Khanh has $n$ points on the Cartesian plane, denoted by $a_1, a_2, \ldots, a_n$. All points' coordinates are integers between $-10^9$ and $10^9$, inclusive. No three points are collinear. He says that these points are vertices of a convex polygon; in other words, there exists a permutation $p_1, p_2, \ldots, p_n$ of integers from $1$ to $n$ such that the polygon $a_{p_1} a_{p_2} \ldots a_{p_n}$ is convex and vertices are listed in counter-clockwise order.

Khanh gives you the number $n$, but hides the coordinates of his points. Your task is to guess the above permutation by asking multiple queries. In each query, you give Khanh $4$ integers $t$, $i$, $j$, $k$; where either $t = 1$ or $t = 2$; and $i$, $j$, $k$ are three distinct indices from $1$ to $n$, inclusive. In response, Khanh tells you:

* if $t = 1$, the area of the triangle $a_ia_ja_k$ multiplied by $2$.
* if $t = 2$, the sign of the cross product of two vectors $\overrightarrow{a_ia_j}$ and $\overrightarrow{a_ia_k}$.

Recall that the cross product of vector $\overrightarrow{a} = (x_a, y_a)$ and vector $\overrightarrow{b} = (x_b, y_b)$ is the integer $x_a \cdot y_b - x_b \cdot y_a$. The sign of a number is $1$ it it is positive, and $-1$ otherwise. It can be proven that the cross product obtained in the above queries can not be $0$.

You can ask at most $3 \cdot n$ queries.

Please note that Khanh fixes the coordinates of his points and does not change it while answering your queries. You do not need to guess the coordinates. In your permutation $a_{p_1}a_{p_2}\ldots a_{p_n}$, $p_1$ should be equal to $1$ and the indices of vertices should be listed in counter-clockwise order.

Interaction

You start the interaction by reading $n$ ($3 \leq n \leq 1\,000$) — the number of vertices.

To ask a query, write $4$ integers $t$, $i$, $j$, $k$ ($1 \leq t \leq 2$, $1 \leq i, j, k \leq n$) in a separate line. $i$, $j$ and $k$ should be distinct.

Then read a single integer to get the answer to this query, as explained above. It can be proven that the answer of a query is always an integer.

When you find the permutation, write a number $0$. Then write $n$ integers $p_1, p_2, \ldots, p_n$ in the same line.

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 documentation for other languages.

Example

Input

```
6

15

-1

1
```

Output

```
1 1 4 6

2 1 5 6

2 2 1 4

0 1 3 4 2 6 5
```

Note

The image below shows the hidden polygon in the example:

 ![](https://espresso.codeforces.com/3dfb379fcb3da2fb7f4c5654afd8b5b84437b215.png)

The interaction in the example goes as below:

* Contestant reads $n = 6$.
* Contestant asks a query with $t = 1$, $i = 1$, $j = 4$, $k = 6$.
* Jury answers $15$. The area of the triangle $A_1A_4A_6$ is $7.5$. Note that the answer is two times the area of the triangle.
* Contestant asks a query with $t = 2$, $i = 1$, $j = 5$, $k = 6$.
* Jury answers $-1$. The cross product of $\overrightarrow{A_1A_5} = (2, 2)$ and $\overrightarrow{A_1A_6} = (4, 1)$ is $-2$. The sign of $-2$ is $-1$.
* Contestant asks a query with $t = 2$, $i = 2$, $j = 1$, $k = 4$.
* Jury answers $1$. The cross product of $\overrightarrow{A_2A_1} = (-5, 2)$ and $\overrightarrow{A_2A_4} = (-2, -1)$ is $1$. The sign of $1$ is $1$.
* Contestant says that the permutation is $(1, 3, 4, 2, 6, 5)$.

#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

struct Point {
    long long x, y;
    int idx;
};

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 __int128 cross3(const Point& o, const Point& a, const Point& b) {
    __int128 ax = (__int128)a.x - o.x;
    __int128 ay = (__int128)a.y - o.y;
    __int128 bx = (__int128)b.x - o.x;
    __int128 by = (__int128)b.y - o.y;
    return ax * by - ay * bx;
}

static vector<Point> convexHullAllCCW(vector<Point> pts) {
    sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) {
        if (a.x != b.x) return a.x < b.x;
        if (a.y != b.y) return a.y < b.y;
        return a.idx < b.idx;
    });

    int n = (int)pts.size();
    vector<Point> hull;
    hull.reserve(n * 2);

    for (int i = 0; i < n; i++) {
        while ((int)hull.size() >= 2) {
            int m = (int)hull.size();
            __int128 cr = cross3(hull[m - 2], hull[m - 1], pts[i]);
            if (cr > 0) break;
            hull.pop_back();
        }
        hull.push_back(pts[i]);
    }

    int lowerSize = (int)hull.size();
    for (int i = n - 2; i >= 0; i--) {
        while ((int)hull.size() > lowerSize) {
            int m = (int)hull.size();
            __int128 cr = cross3(hull[m - 2], hull[m - 1], pts[i]);
            if (cr > 0) break;
            hull.pop_back();
        }
        hull.push_back(pts[i]);
    }

    if (!hull.empty()) hull.pop_back();

    auto signedArea2 = [&](const vector<Point>& p) -> __int128 {
        __int128 s = 0;
        int m = (int)p.size();
        for (int i = 0; i < m; i++) {
            int j = (i + 1) % m;
            s += (__int128)p[i].x * p[j].y - (__int128)p[i].y * p[j].x;
        }
        return s;
    };

    if ((int)hull.size() >= 3) {
        __int128 a2 = signedArea2(hull);
        if (a2 < 0) reverse(hull.begin(), hull.end());
    }
    return hull;
}

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

    try {
        int n = inf.readInt(3, 1000, "n");

        vector<Point> pts(n + 1);
        vector<Point> list;
        list.reserve(n);

        for (int i = 1; i <= n; i++) {
            long long x = inf.readLong(-1000000000LL, 1000000000LL, "x");
            long long y = inf.readLong(-1000000000LL, 1000000000LL, "y");
            pts[i] = Point{x, y, i};
            list.push_back(pts[i]);
        }

        query_limit = 3LL * n;
        long long hard_cap = max(200000LL, 10LL * query_limit);

        log_metrics();

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

        vector<Point> hull = convexHullAllCCW(list);
        if ((int)hull.size() != n) {
            finish(_pe, "interactor error: points are not all on convex hull");
        }

        int pos1 = -1;
        for (int i = 0; i < n; i++) {
            if (hull[i].idx == 1) {
                pos1 = i;
                break;
            }
        }
        if (pos1 == -1) {
            finish(_pe, "interactor error: index 1 not found");
        }

        vector<int> expected;
        expected.reserve(n);
        for (int t = 0; t < n; t++) expected.push_back(hull[(pos1 + t) % n].idx);

        while (true) {
            long long t;
            if (!(cin >> t)) {
                finish(_pe, "unexpected EOF from contestant");
            }

            if (t == 0) {
                vector<int> ans(n);
                for (int i = 0; i < n; i++) {
                    long long v;
                    if (!(cin >> v)) finish(_pe, "missing permutation element(s)");
                    if (v < INT_MIN || v > INT_MAX) finish(_pe, "permutation element out of range");
                    ans[i] = (int)v;
                }

                if (ans[0] != 1) finish(_wa, "p1 must be 1");

                vector<int> seen(n + 1, 0);
                for (int i = 0; i < n; i++) {
                    if (ans[i] < 1 || ans[i] > n) finish(_wa, "permutation index out of [1..n]");
                    if (seen[ans[i]]++) finish(_wa, "permutation contains duplicates");
                }

                if (ans != expected) finish(_wa, "wrong permutation");
                finish(_ok, "OK");
            }

            if (t != 1 && t != 2) {
                finish(_pe, "invalid query type");
            }

            long long ii, jj, kk;
            if (!(cin >> ii >> jj >> kk)) {
                finish(_pe, "malformed query");
            }
            if (ii < 1 || ii > n || jj < 1 || jj > n || kk < 1 || kk > n) {
                finish(_pe, "query index out of range");
            }
            if (ii == jj || ii == kk || jj == kk) {
                finish(_pe, "query indices must be distinct");
            }

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

            const Point& A = pts[(int)ii];
            const Point& B = pts[(int)jj];
            const Point& C = pts[(int)kk];
            __int128 cr = cross3(A, B, C);

            if (t == 1) {
                __int128 v = cr;
                if (v < 0) v = -v;
                long long out = (long long)v;
                cout << out << "\n" << flush;
            } else {
                int sgn = (cr > 0) ? 1 : -1;
                cout << sgn << "\n" << flush;
            }
        }
    } catch (const exception& e) {
        finish(_pe, string("interactor exception: ") + e.what());
    } catch (...) {
        finish(_pe, "interactor exception");
    }
}

#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

struct Pt {
    long long x, y;
    int id;
};

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 __int128 cross128(long long ax, long long ay, long long bx, long long by) {
    return (__int128)ax * (__int128)by - (__int128)ay * (__int128)bx;
}

static __int128 cross128(const Pt& o, const Pt& a, const Pt& b) {
    return cross128(a.x - o.x, a.y - o.y, b.x - o.x, b.y - o.y);
}

static long long i128_to_ll_checked(__int128 v) {
    if (v < (__int128)LLONG_MIN || v > (__int128)LLONG_MAX) return 0;
    return (long long)v;
}

struct SplitMix64 {
    uint64_t x;
    explicit SplitMix64(uint64_t seed) : x(seed) {}
    uint64_t nextU64() {
        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);
        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
        return z ^ (z >> 31);
    }
    long long nextLL(long long lo, long long hi) {
        if (lo > hi) std::swap(lo, hi);
        uint64_t span = (uint64_t)(hi - lo + 1);
        uint64_t r = nextU64();
        return lo + (long long)(r % span);
    }
    int nextInt(int lo, int hi) { return (int)nextLL(lo, hi); }
};

static long long llabsll(long long v) { return v < 0 ? -v : v; }

static long long gcdll(long long a, long long b) {
    a = llabsll(a);
    b = llabsll(b);
    while (b) {
        long long t = a % b;
        a = b;
        b = t;
    }
    return a;
}

static vector<long long> pickUniqueDet(int n, long long lo, long long hi, SplitMix64& rng) {
    set<long long> s;
    while ((int)s.size() < n) {
        s.insert(rng.nextLL(lo, hi));
    }
    return vector<long long>(s.begin(), s.end());
}

template <class T>
static void shuffleDet(vector<T>& v, SplitMix64& rng) {
    for (int i = (int)v.size() - 1; i > 0; --i) {
        int j = rng.nextInt(0, i);
        swap(v[i], v[j]);
    }
}

struct Vec {
    long long x, y;
};

static __int128 crossVec(const Vec& a, const Vec& b) {
    return (__int128)a.x * (__int128)b.y - (__int128)a.y * (__int128)b.x;
}

static int halfPlane(const Vec& v) {
    if (v.y > 0) return 1;
    if (v.y < 0) return 0;
    return v.x > 0 ? 1 : 0;
}

static bool isStrictlyConvexCCW(const vector<pair<long long, long long>>& poly) {
    int n = (int)poly.size();
    if (n < 3) return false;
    __int128 sign = 0;
    for (int i = 0; i < n; i++) {
        auto o = poly[i];
        auto a = poly[(i + 1) % n];
        auto b = poly[(i + 2) % n];
        __int128 cr = cross128(a.first - o.first, a.second - o.second, b.first - o.first, b.second - o.second);
        if (cr == 0) return false;
        if (sign == 0) sign = (cr > 0 ? 1 : -1);
        else if ((cr > 0 ? 1 : -1) != sign) return false;
    }
    return sign > 0;
}

static vector<pair<long long, long long>> genConvexValtrDet(int n, long long W, long long H, uint64_t seed) {
    SplitMix64 rng(seed);

    vector<long long> xs = pickUniqueDet(n, 0, W, rng);
    vector<long long> ys = pickUniqueDet(n, 0, H, rng);
    sort(xs.begin(), xs.end());
    sort(ys.begin(), ys.end());

    auto splitDiffs = [&](const vector<long long>& v) -> vector<long long> {
        vector<long long> upper, lower;
        long long lastU = v[0], lastL = v[0];
        for (int i = 1; i <= n - 2; i++) {
            if (rng.nextInt(0, 1) == 0) {
                upper.push_back(v[i] - lastU);
                lastU = v[i];
            } else {
                lower.push_back(v[i] - lastL);
                lastL = v[i];
            }
        }
        upper.push_back(v[n - 1] - lastU);
        lower.push_back(v[n - 1] - lastL);

        vector<long long> res;
        res.reserve(n);
        for (long long d : upper) res.push_back(d);
        for (long long d : lower) res.push_back(-d);
        return res;
    };

    vector<long long> dx = splitDiffs(xs);
    vector<long long> dy = splitDiffs(ys);
    shuffleDet(dy, rng);

    vector<Vec> edges(n);
    for (int i = 0; i < n; i++) edges[i] = Vec{dx[i], dy[i]};

    sort(edges.begin(), edges.end(), [&](const Vec& a, const Vec& b) {
        int ha = halfPlane(a), hb = halfPlane(b);
        if (ha != hb) return ha > hb;
        __int128 cr = crossVec(a, b);
        if (cr != 0) return cr > 0;
        long long la = llabsll(a.x) + llabsll(a.y);
        long long lb = llabsll(b.x) + llabsll(b.y);
        return la < lb;
    });

    vector<pair<long long, long long>> poly;
    poly.reserve(n);
    long long cx = 0, cy = 0;
    for (int i = 0; i < n; i++) {
        cx += edges[i].x;
        cy += edges[i].y;
        poly.push_back({cx, cy});
    }

    long long minx = poly[0].first, miny = poly[0].second;
    for (auto& p : poly) {
        minx = min(minx, p.first);
        miny = min(miny, p.second);
    }
    for (auto& p : poly) {
        p.first -= minx;
        p.second -= miny;
    }
    return poly;
}

static vector<Pt> convexHullStrict(vector<Pt> pts) {
    sort(pts.begin(), pts.end(), [&](const Pt& a, const Pt& b) {
        if (a.x != b.x) return a.x < b.x;
        if (a.y != b.y) return a.y < b.y;
        return a.id < b.id;
    });
    int n = (int)pts.size();
    if (n <= 1) return pts;

    vector<Pt> lower, upper;
    for (const auto& p : pts) {
        while ((int)lower.size() >= 2 && cross128(lower[(int)lower.size() - 2], lower.back(), p) <= 0) lower.pop_back();
        lower.push_back(p);
    }
    for (int i = n - 1; i >= 0; --i) {
        const auto& p = pts[i];
        while ((int)upper.size() >= 2 && cross128(upper[(int)upper.size() - 2], upper.back(), p) <= 0) upper.pop_back();
        upper.push_back(p);
    }

    lower.pop_back();
    upper.pop_back();
    lower.insert(lower.end(), upper.begin(), upper.end());
    return lower;
}

static bool hasAnyThreeCollinear(const vector<Pt>& pts) {
    int n = (int)pts.size();
    vector<pair<long long, long long>> dirs;
    dirs.reserve(n - 1);
    for (int i = 0; i < n; i++) {
        dirs.clear();
        for (int j = 0; j < n; j++) if (j != i) {
            long long dx = pts[j].x - pts[i].x;
            long long dy = pts[j].y - pts[i].y;
            long long g = gcdll(dx, dy);
            dx /= g;
            dy /= g;
            if (dx < 0 || (dx == 0 && dy < 0)) {
                dx = -dx;
                dy = -dy;
            }
            dirs.push_back({dx, dy});
        }
        sort(dirs.begin(), dirs.end());
        for (int k = 1; k < (int)dirs.size(); k++) {
            if (dirs[k] == dirs[k - 1]) return true;
        }
    }
    return false;
}

static vector<Pt> buildDeterministicInstanceFromN(int n) {
    const long long LIM = 1000000000LL;
    const long long W = 700000000LL;
    const long long H = 700000000LL;

    uint64_t baseSeed = 0x1234567890abcdefULL ^ (uint64_t)n * 0x9e3779b97f4a7c15ULL;

    vector<pair<long long, long long>> poly;
    for (int attempt = 0; attempt < 64; attempt++) {
        uint64_t seed = baseSeed + (uint64_t)attempt * 0xD1B54A32D192ED03ULL;
        poly = genConvexValtrDet(n, W, H, seed);

        if (!isStrictlyConvexCCW(poly)) {
            reverse(poly.begin(), poly.end());
        }
        if (!isStrictlyConvexCCW(poly)) continue;

        long long minx = poly[0].first, miny = poly[0].second;
        long long maxx = poly[0].first, maxy = poly[0].second;
        for (auto& p : poly) {
            minx = min(minx, p.first);
            miny = min(miny, p.second);
            maxx = max(maxx, p.first);
            maxy = max(maxy, p.second);
        }
        long long sx = -((minx + maxx) / 2);
        long long sy = -((miny + maxy) / 2);
        for (auto& p : poly) {
            p.first += sx;
            p.second += sy;
            if (p.first < -LIM || p.first > LIM || p.second < -LIM || p.second > LIM) {
                sx = sy = 0;
                break;
            }
        }
        bool inRange = true;
        for (auto& p : poly) {
            if (p.first < -LIM || p.first > LIM || p.second < -LIM || p.second > LIM) {
                inRange = false;
                break;
            }
        }
        if (!inRange) continue;

        vector<Pt> tmp;
        tmp.reserve(n);
        for (int i = 0; i < n; i++) tmp.push_back(Pt{poly[i].first, poly[i].second, i + 1});
        if (hasAnyThreeCollinear(tmp)) continue;

        vector<Pt> hull = convexHullStrict(tmp);
        if ((int)hull.size() != n) continue;

        SplitMix64 rng(seed ^ 0xA5A5A5A5A5A5A5A5ULL);
        int pos1 = (n <= 6 ? 0 : rng.nextInt(0, n - 1));

        vector<Pt> coords(n + 1);
        coords[1] = Pt{poly[pos1].first, poly[pos1].second, 1};

        vector<int> pos;
        pos.reserve(n - 1);
        for (int i = 0; i < n; i++) if (i != pos1) pos.push_back(i);
        shuffleDet(pos, rng);

        for (int idx = 2; idx <= n; idx++) {
            int p = pos[idx - 2];
            coords[idx] = Pt{poly[p].first, poly[p].second, idx};
        }

        vector<Pt> all;
        all.reserve(n);
        for (int i = 1; i <= n; i++) all.push_back(coords[i]);
        vector<Pt> hull2 = convexHullStrict(all);
        if ((int)hull2.size() != n) continue;
        if (hasAnyThreeCollinear(all)) continue;

        return coords;
    }

    int m = n / 2;
    long long D = 500000000LL;
    vector<pair<long long, long long>> fallback;
    fallback.reserve(n);
    for (int i = 0; i <= m; i++) fallback.push_back({i, 1LL * i * i});
    if (n % 2 == 0) {
        for (int i = m - 1; i >= 1; --i) fallback.push_back({i, -1LL * i * i - D});
    } else {
        for (int i = m; i >= 1; --i) fallback.push_back({i, -1LL * i * i - D});
    }
    if (!isStrictlyConvexCCW(fallback)) reverse(fallback.begin(), fallback.end());

    vector<Pt> coords(n + 1);
    for (int i = 1; i <= n; i++) {
        coords[i] = Pt{fallback[i - 1].first, fallback[i - 1].second, i};
    }
    return coords;
}

static bool readLongLongSafe(long long& out) {
    if (!(cin >> out)) return false;
    return true;
}

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

    int n = inf.readInt();
    if (n < 3 || n > 1000) finish(_pe, "invalid n in input");

    vector<Pt> coords(n + 1);
    bool hasCoords = false;

    if (!inf.seekEof()) {
        hasCoords = true;
        for (int i = 1; i <= n; i++) {
            long long x = inf.readLong();
            long long y = inf.readLong();
            coords[i] = Pt{x, y, i};
        }
    } else {
        coords = buildDeterministicInstanceFromN(n);
    }

    query_limit = 3LL * n;
    log_metrics();

    cout << n << endl;

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

    auto triangleCross = [&](int i, int j, int k) -> __int128 {
        long long x1 = coords[j].x - coords[i].x;
        long long y1 = coords[j].y - coords[i].y;
        long long x2 = coords[k].x - coords[i].x;
        long long y2 = coords[k].y - coords[i].y;
        return cross128(x1, y1, x2, y2);
    };

    auto getCorrectOrder = [&]() -> vector<int> {
        vector<Pt> pts;
        pts.reserve(n);
        for (int i = 1; i <= n; i++) pts.push_back(coords[i]);
        vector<Pt> hull = convexHullStrict(pts);
        if ((int)hull.size() != n) finish(_pe, "internal: points are not all hull vertices");
        int pos1 = -1;
        for (int i = 0; i < n; i++) if (hull[i].id == 1) { pos1 = i; break; }
        if (pos1 == -1) finish(_pe, "internal: point 1 not found on hull");
        vector<int> order;
        order.reserve(n);
        for (int i = 0; i < n; i++) order.push_back(hull[(pos1 + i) % n].id);
        return order;
    };

    while (true) {
        long long tll;
        if (!readLongLongSafe(tll)) finish(_pe, "unexpected EOF from contestant");
        if (tll == 0) {
            vector<int> ans(n);
            for (int i = 0; i < n; i++) {
                long long v;
                if (!readLongLongSafe(v)) finish(_pe, "missing permutation after 0");
                if (v < 1 || v > n) finish(_pe, "permutation element out of range");
                ans[i] = (int)v;
            }
            if (ans[0] != 1) finish(_wa, "p1 must be 1");
            vector<int> seen(n + 1, 0);
            for (int v : ans) {
                if (seen[v]) finish(_pe, "permutation contains duplicates");
                seen[v] = 1;
            }
            vector<int> correct = getCorrectOrder();
            if (ans == correct) finish(_ok, "correct");
            finish(_wa, "wrong order");
        }

        int t = (int)tll;
        if (!(t == 1 || t == 2)) finish(_pe, "invalid query type");
        long long ill, jll, kll;
        if (!readLongLongSafe(ill) || !readLongLongSafe(jll) || !readLongLongSafe(kll)) finish(_pe, "incomplete query");
        int i = (int)ill, j = (int)jll, k = (int)kll;
        if (i < 1 || i > n || j < 1 || j > n || k < 1 || k > n) finish(_pe, "index out of range");
        if (i == j || i == k || j == k) finish(_pe, "indices must be distinct");

        queries++;
        if (queries > hard_cap) finish(_pe, "too many queries (hard cap exceeded)");

        __int128 cr = triangleCross(i, j, k);
        if (cr == 0) finish(_pe, "internal: collinear triple encountered");

        if (t == 2) {
            long long res = (cr > 0 ? 1 : -1);
            cout << res << endl;
        } else {
            __int128 v = cr;
            if (v < 0) v = -v;
            long long res = i128_to_ll_checked(v);
            if (res <= 0) finish(_pe, "internal: non-positive area");
            cout << res << endl;
        }
    }
}

#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

struct Vec {
    ll x, y;
};

static ll cross(const Vec& a, const Vec& b) {
    return a.x * b.y - a.y * b.x;
}

static ll cross3(const pair<ll, ll>& o, const pair<ll, ll>& a, const pair<ll, ll>& b) {
    return (a.first - o.first) * (b.second - o.second) - (a.second - o.second) * (b.first - o.first);
}

template <class T>
static void shuffleVec(vector<T>& v) {
    for (int i = (int)v.size() - 1; i > 0; --i) {
        int j = rnd.next(0, i);
        swap(v[i], v[j]);
    }
}

static vector<ll> pickUnique(int n, ll lo, ll hi) {
    set<ll> s;
    while ((int)s.size() < n) s.insert(rnd.next(lo, hi));
    return vector<ll>(s.begin(), s.end());
}

static bool isStrictlyConvexCCW(vector<pair<ll, ll>>& poly) {
    int n = (int)poly.size();
    if (n < 3) return false;

    ll sign = 0;
    for (int i = 0; i < n; i++) {
        ll cr = cross3(poly[i], poly[(i + 1) % n], poly[(i + 2) % n]);
        if (cr == 0) return false;
        if (sign == 0) sign = (cr > 0 ? 1 : -1);
        else if ((cr > 0 ? 1 : -1) != sign) return false;
    }
    if (sign < 0) reverse(poly.begin(), poly.end());
    return true;
}

static vector<pair<ll, ll>> genConvexValtr(int n, ll W, ll H) {
    vector<ll> xs = pickUnique(n, 0, W);
    vector<ll> ys = pickUnique(n, 0, H);
    sort(xs.begin(), xs.end());
    sort(ys.begin(), ys.end());

    auto splitDiffs = [&](const vector<ll>& v) -> vector<ll> {
        vector<ll> upper, lower;
        ll lastU = v[0], lastL = v[0];
        for (int i = 1; i <= n - 2; i++) {
            if (rnd.next(0, 1) == 0) {
                upper.push_back(v[i] - lastU);
                lastU = v[i];
            } else {
                lower.push_back(v[i] - lastL);
                lastL = v[i];
            }
        }
        upper.push_back(v[n - 1] - lastU);
        lower.push_back(v[n - 1] - lastL);

        vector<ll> res;
        res.reserve(n);
        for (ll d : upper) res.push_back(d);
        for (ll d : lower) res.push_back(-d);
        return res;
    };

    vector<ll> dx = splitDiffs(xs);
    vector<ll> dy = splitDiffs(ys);
    shuffleVec(dy);

    vector<Vec> edges(n);
    for (int i = 0; i < n; i++) edges[i] = Vec{dx[i], dy[i]};

    auto half = [&](const Vec& v) -> int {
        if (v.y > 0) return 1;
        if (v.y < 0) return 0;
        return v.x > 0 ? 1 : 0;
    };

    sort(edges.begin(), edges.end(), [&](const Vec& a, const Vec& b) {
        int ha = half(a), hb = half(b);
        if (ha != hb) return ha > hb;
        ll cr = cross(a, b);
        if (cr != 0) return cr > 0;
        ll la = llabs(a.x) + llabs(a.y);
        ll lb = llabs(b.x) + llabs(b.y);
        return la < lb;
    });

    vector<pair<ll, ll>> poly;
    poly.reserve(n);
    ll cx = 0, cy = 0;
    for (int i = 0; i < n; i++) {
        cx += edges[i].x;
        cy += edges[i].y;
        poly.push_back({cx, cy});
    }

    ll minx = poly[0].first, miny = poly[0].second;
    ll maxx = poly[0].first, maxy = poly[0].second;
    for (auto& p : poly) {
        minx = min(minx, p.first);
        miny = min(miny, p.second);
        maxx = max(maxx, p.first);
        maxy = max(maxy, p.second);
    }
    for (auto& p : poly) {
        p.first -= minx;
        p.second -= miny;
    }
    return poly;
}

static vector<pair<ll, ll>> buildInstanceNon(int seed, int n, ll lim) {
    if (seed == 1) {
        vector<pair<ll, ll>> pts = {
            {lim, 0},
            {0, lim},
            {-lim, -lim}
        };
        return pts;
    }
    if (seed == 2) {
        vector<pair<ll, ll>> pts = {
            {-lim, -1},
            {lim, -1},
            {lim, 1},
            {-lim, 1}
        };
        return pts;
    }

    ll W = lim, H = lim;
    if (seed == 3) {
        W = lim;
        H = 2000000;
        if (H < n + 10) H = (ll)n + 10;
    } else {
        int shape = rnd.next(0, 2);
        if (shape == 0) {
            W = lim;
            H = rnd.next(2000000LL, 30000000LL);
            if (H < n + 10) H = (ll)n + 10;
        } else if (shape == 1) {
            H = lim;
            W = rnd.next(2000000LL, 30000000LL);
            if (W < n + 10) W = (ll)n + 10;
        } else {
            W = lim;
            H = lim;
        }
    }

    for (int attempt = 0; attempt < 200; attempt++) {
        vector<pair<ll, ll>> poly = genConvexValtr(n, W, H);
        if (!isStrictlyConvexCCW(poly)) continue;

        ll maxx = poly[0].first, maxy = poly[0].second;
        ll minx = poly[0].first, miny = poly[0].second;
        for (auto& p : poly) {
            minx = min(minx, p.first);
            miny = min(miny, p.second);
            maxx = max(maxx, p.first);
            maxy = max(maxy, p.second);
        }
        for (auto& p : poly) {
            p.first -= minx;
            p.second -= miny;
        }
        maxx -= minx;
        maxy -= miny;

        if (maxx > 2 * lim || maxy > 2 * lim) continue;

        ll txLo = -lim;
        ll txHi = lim - maxx;
        ll tyLo = -lim;
        ll tyHi = lim - maxy;
        if (txLo > txHi || tyLo > tyHi) continue;

        ll tx = rnd.next(txLo, txHi);
        ll ty = rnd.next(tyLo, tyHi);
        for (auto& p : poly) {
            p.first += tx;
            p.second += ty;
            if (p.first < -lim || p.first > lim || p.second < -lim || p.second > lim) {
                tx = ty = 0;
                break;
            }
        }

        bool ok = true;
        for (auto& p : poly) {
            if (p.first < -lim || p.first > lim || p.second < -lim || p.second > lim) {
                ok = false;
                break;
            }
        }
        if (!ok) continue;

        if (!isStrictlyConvexCCW(poly)) continue;
        return poly;
    }

    vector<pair<ll, ll>> pts;
    for (int i = 0; i < n; i++) pts.push_back({-lim + i, -lim + 2LL * i + 1});
    return pts;
}

static vector<pair<ll, ll>> assignIndices(const vector<pair<ll, ll>>& polyCCW, int seed) {
    int n = (int)polyCCW.size();
    vector<pair<ll, ll>> coords(n + 1);

    int pos1;
    if (n <= 6) pos1 = 0;
    else if (seed == 3) pos1 = n / 2;
    else pos1 = rnd.next(0, n - 1);

    coords[1] = polyCCW[pos1];

    vector<int> pos;
    pos.reserve(n - 1);
    for (int i = 0; i < n; i++) if (i != pos1) pos.push_back(i);
    shuffleVec(pos);

    for (int idx = 2; idx <= n; idx++) coords[idx] = polyCCW[pos[idx - 2]];
    return coords;
}

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

    string mode = opt<string>("mode", "non");
    int nOpt = opt<int>("n", 1000);
    ll lim = opt<ll>("limit", 1000000000LL);

    int seed = 0;
    if (argc >= 2) seed = atoi(argv[1]);

    auto clampN = [&](int n) -> int {
        n = max(3, min(1000, n));
        return n;
    };

    int n;
    if (seed == 1) n = 3;
    else if (seed == 2) n = 4;
    else if (seed == 3) n = 1000;
    else {
        n = clampN(nOpt);
        if (n >= 10) {
            int lo = max(3, n - 50);
            n = rnd.next(lo, n);
        }
    }

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

    if (mode != "non") mode = "non";

    vector<pair<ll, ll>> poly = buildInstanceNon(seed, n, lim);
    if ((int)poly.size() != n) {
        poly.resize(n);
    }

    vector<pair<ll, ll>> tmp = poly;
    isStrictlyConvexCCW(tmp);

    vector<pair<ll, ll>> coords = assignIndices(tmp, seed);

    cout << n << "\n";
    for (int i = 1; i <= n; i++) {
        cout << coords[i].first << " " << coords[i].second << "\n";
    }
    return 0;
}


Entrapment is an asymmetric two-player game that is played on a $3 \times 3$ square grid. The two players are called the Runner and the Trapper. The grid squares are numbered from 1 to 9 as depicted below:

1	23	23

4	5	6

7	89	89

Before starting the game, the players agree on the number of rounds that the game will last, and on the starting state of the game board. Up to 8 of the grid squares can be marked as unavailable. The players also choose who will be the Runner and who will be the Trapper. The Runner then secretly chooses a starting square from among those that are available (i.e., are not marked as unavailable) but does not tell the Trapper their choice.

Each of the game rounds consists of the following steps, in order:

1. The Trapper publicly chooses some subset of the available squares (the empty set is allowed) and asks the Runner, “Are you currently in any of these squares?”
2. The Runner answers truthfully whether or not they are in any of the chosen squares.
3. The Trapper publicly chooses exactly one available square. That square becomes unavailable for the rest of the game. (The Runner might currently reside in that square; if so, nothing special happens.)
4. The Runner secretly moves from their current square to an available orthogonally-adjacent square. If no such square exists, the Runner announces that they are trapped and the Trapper wins the game.

If the Runner has not been trapped by the end of the last round, they prove to the Trapper that they answered all questions truthfully by revealing their choice of starting square and the move that they made during each round. The Runner then wins the game.

Because the Runner’s initial choice of square is secret, as are all of their subsequent moves, the Runner is allowed to “cheat” by not truly committing to a square. At the end of the game, if the Runner can produce a choice of starting square and subsequent moves that do not result in being trapped and are consistent with the answers to the Trapper’s questions during each round, that is enough for the Runner to win the game.

2025 ICPC North America Championship Problem C: Entrapment

# Interaction

This is an interactive problem. Given the number of game rounds and the set of squares that are initially marked unavailable, determine whether the Runner or the Trapper would win assuming optimal play, and then prove it by playing as that role against the judge. The judge will obey all game rules, but may or may not play optimally.

Interaction starts by reading a line of 2 space-separated integers $R$ and $U$ $1 \leq R \leq 9$ , $0 \leq U \leq 8$ , $R + U \le 9 )$ ): the number of rounds in the game and the number of squares that are unavailable at the start of the game.

Next, if $U > 0$ , read a line of $U$ space-separated integers $s$ ( $1 \leq s \leq 9$ ): the labels of the squares that are unavailable at the start of the game. Please refer to the diagram above for how the squares in the grid are labeled. The $U$ labels are guaranteed to be distinct.

Determine whether the Runner or Trapper would win the game with optimal play, given the starting board and number of game rounds. Print a line of output with the string Runner if the runner wins with optimal play, and the string Trapper otherwise. You will play as that role for the rest of the game; please see the appropriate section below for further instructions on how to interact with the judge in that role.

For the Runner, repeat the following steps $R$ times:

• Read a line of input with a single integer $N$ : the size of the subset of available squares that the Trapper has chosen to ask about. $N$ is guaranteed to be between 0 and the number of available squares left on the board, inclusive.
• If $N > 0$ , read a line of $N$ space-separated integers $\ell$ $1 \leq \ell \leq 9 ,$ ) listing the labels of the squares in the Trapper’s chosen subset. The labels are guaranteed to be distinct and all of the chosen squares are guaranteed to be available.
• Print a line of output containing either the string Yes or the string No. The former informs the trapper that you are currently in one of the chosen squares; the latter informs the trapper that you are not.
• Read a line with a single integer $i$ $1 \leq i \leq 9$ ), the label of the square that the Trapper marks as unavailable. It is guaranteed that square $i$ is a formerly-available square.
• Print a line with the string Free to inform the Trapper that you have secretly moved to an orthogonally-adjacent available square and are ready to proceed to the next round. If there are no orthogonally-adjacent squares available, you must print Trapped instead and exit; your submission will be judged incorrect for having failed to elude the Trapper.

After you have played $R$ rounds of the game according to the protocol above, print a line with $R + 1$ space-separated integers. The first integer is the label of your chosen starting square; each of the next $R$ integers are the labels of the squares onto which you moved at the end of each of the $R$ rounds. Your moves must be legal and must be consistent with the answers you gave to the Trapper’s queries during each round of play. After printing this line, your program must exit.

For the Trapper, repeat the following steps $R$ times:

• Print a line with a single integer $N$ : the size of the subset of available squares that you would like to ask the Runner about.
• If $N > 0$ , print a line of $N$ space-separated integers listing the available squares to ask the Runner about. You may list the labels in any order, but the labels must be distinct and must refer to available squares.
• Read a line of input containing a single string: Yes if the Runner is in one of your chosen squares, or $\tt N O$ otherwise.
• Print a line with a single integer $i$ : the square that you are marking unavailable. The label $i$ must be a valid currently-available square.
• Read a line with a single string: Free if the Runner has moved to an available square, or Trapped if they were unable to do so. After reading the word Trapped, you have won the game, and your program must exit. If you read the word Free at the end of the Rth round, your program must also exit, though your submission will be judged incorrect since you have failed to trap the Runner.

The judge is guaranteed to answer all questions truthfully.

# Notes

Do not forget to flush the output stream after each line that you print and to cleanly exit after the interaction is done. Please also make sure that you follow the above interaction protocol exactly regarding what information to print on which line of output: for example, if the protocol requires you to print a list of space-separated integers on a single line, the judge will not accept each integer on its own line.

If the judge receives invalid or unexpected input, it will print $- 1$ and then immediately exit. Your program must detect this error report and cleanly exit in order to receive a Wrong Answer verdict. If your program blocks waiting for further interaction from the judge, or tries to interpret the $- 1$ as a game move, you may receive a different rejected verdict (such as Time Limit Exceeded or Runtime Error) instead of Wrong Answer.

2025 ICPC North America Championship Problem C: Entrapment

You have been provided with a command-line tool for local testing. The tool has comments at the top to explain its use.

Read                                     Sample Interaction 1                                     Write36123789

36123789

	Trapper245

Yes

	5

Free

	0

No

	6

Trapped

# Sample Interaction 2

Write

20

	Runner

73128945

	Yes

5

	Free

44678

	Yes

7

	Free541

#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;

static int R_game, U_game;
static vector<int> unavailable_init;
static int queries = 0;
static int query_limit = 0;

static vector<vector<int>> adj(10);

static vector<vector<vector<bool>>> dp;

inline bool has(int mask, int i) {
    return (mask >> (i - 1)) & 1;
}

inline int with_bit(int mask, int i) {
    return mask | (1 << (i - 1));
}

inline int without_bit(int mask, int i) {
    return mask & ~(1 << (i - 1));
}

int expand_set(int p, int m) {
    int res = 0;
    for (int i = 1; i <= 9; ++i) {
        if (has(p, i)) {
            for (int nxt : adj[i]) {
                if (has(m, nxt)) {
                    res = with_bit(res, nxt);
                }
            }
        }
    }
    return res;
}

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

void init_adj() {

    auto add = [&](int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    };

    add(1, 2); add(2, 3);
    add(4, 5); add(5, 6);
    add(7, 8); add(8, 9);

    add(1, 4); add(4, 7);
    add(2, 5); add(5, 8);
    add(3, 6); add(6, 9);
}

void precompute_dp() {
    dp.assign(R_game + 1, vector<vector<bool>>(512, vector<bool>(512, false)));

    for (int m = 0; m < 512; ++m) {
        for (int p = 0; p < 512; ++p) {
            dp[0][m][p] = (p == 0);
        }
    }

    for (int r = 1; r <= R_game; ++r) {
        for (int m = 0; m < 512; ++m) {

            static bool g[512];

            for (int s = m; ; s = (s - 1) & m) {
                bool exists_winning_block = false;
                for (int i = 1; i <= 9; ++i) {
                    if (has(m, i)) {
                        int nm = without_bit(m, i);
                        int np = expand_set(s, nm);
                        if (dp[r-1][nm][np]) {
                            exists_winning_block = true;
                            break;
                        }
                    }
                }

                if (s == 0) exists_winning_block = true;

                g[s] = exists_winning_block;
                if (s == 0) break;
            }

            for (int p = m; ; p = (p - 1) & m) {
                bool can_split = false;
                if (g[p]) {
                    can_split = true;
                } else {
                    for (int a = p; a > 0; a = (a - 1) & p) {
                        int b_part = p ^ a;
                        if (g[a] && g[b_part]) {
                            can_split = true;
                            break;
                        }
                    }
                }
                dp[r][m][p] = can_split;
                if (p == 0) break;
            }
        }
    }
}

void play_as_runner(int initial_mask) {
    int cur_mask = initial_mask;
    int cur_p = cur_mask;

    struct RoundInfo {
        int p_before;
        int q;
        string ans;
        int b;
        int p_after;
    };
    vector<RoundInfo> history;

    for (int r = 1; r <= R_game; ++r) {
        log_metrics();

        int N;
        if (!(cin >> N)) finish(_wa, "Unexpected EOF reading query size");

        int Q = 0;
        if (N < 0 || N > 9) finish(_wa, "Invalid query size");

        for (int i=0; i<N; ++i) {
            int x;
            if (!(cin >> x)) finish(_wa, "Unexpected EOF reading query list");
            if (x < 1 || x > 9) finish(_wa, "Invalid square label");
            if (!has(cur_mask, x)) finish(_wa, "Query square not available");
            if (has(Q, x)) finish(_wa, "Duplicate square in query");
            Q = with_bit(Q, x);
        }

        int p_yes = cur_p & Q;
        int p_no = cur_p & (~Q);
        int k = R_game - r;

        auto is_trapper_winning = [&](int s) {
            if (s == 0) return true;

            for (int i=1; i<=9; ++i) {
                if (has(cur_mask, i)) {
                    int nm = without_bit(cur_mask, i);
                    int np = expand_set(s, nm);
                    if (dp[k][nm][np]) return true;
                }
            }
            return false;
        };

        bool win_yes = is_trapper_winning(p_yes);
        bool win_no = is_trapper_winning(p_no);

        string my_ans;
        int next_p_initial;

        if (!win_yes && p_yes != 0) {
            my_ans = "Yes";
            next_p_initial = p_yes;
        } else if (!win_no && p_no != 0) {
            my_ans = "No";
            next_p_initial = p_no;
        } else {

            if (p_yes != 0) {
                my_ans = "Yes";
                next_p_initial = p_yes;
            } else {
                my_ans = "No";
                next_p_initial = p_no;
            }
        }

        cout << my_ans << endl;

        int b;
        if (!(cin >> b)) finish(_wa, "Unexpected EOF reading block");
        if (b < 1 || b > 9) finish(_wa, "Invalid block label");
        if (!has(cur_mask, b)) finish(_wa, "Block square not available");

        int mask_after_block = without_bit(cur_mask, b);
        int p_after_move = expand_set(next_p_initial, mask_after_block);

        RoundInfo info;
        info.p_before = cur_p;
        info.q = Q;
        info.ans = my_ans;
        info.b = b;
        info.p_after = next_p_initial;
        history.push_back(info);

        if (p_after_move == 0) {
            cout << "Trapped" << endl;
            queries = r;
            finish(_ok, "Contestant trapped the runner");
        } else {
            cout << "Free" << endl;
            cur_p = p_after_move;
            cur_mask = mask_after_block;
            queries = r;
        }
    }

    vector<int> path;
    int u_curr = -1;
    for(int i=1; i<=9; ++i) if(has(cur_p, i)) { u_curr = i; break; }
    path.push_back(u_curr);

    for (int r = R_game - 1; r >= 0; --r) {
        int u_prev = -1;
        for (int cand=1; cand<=9; ++cand) {
            if (has(history[r].p_after, cand)) {
                bool adj_ok = false;
                for (int nxt : adj[cand]) {
                    if (nxt == u_curr) {
                        adj_ok = true;
                        break;
                    }
                }
                if (adj_ok) {
                    u_prev = cand;
                    break;
                }
            }
        }
        if (u_prev == -1) finish(_fail, "Interactor internal error: path reconstruction failed");
        path.push_back(u_prev);
        u_curr = u_prev;
    }
    reverse(path.begin(), path.end());

    for (int i=0; i < (int)path.size(); ++i) {
        cout << path[i] << (i == (int)path.size() - 1 ? "" : " ");
    }
    cout << endl;

    finish(_wa, "Runner survived");
}

struct TrapHistory {
    int q_mask;
    string ans;
    int b;
};

void play_as_trapper(int initial_mask) {
    int cur_mask = initial_mask;
    int cur_p = initial_mask;
    vector<TrapHistory> hist;

    for (int r = 1; r <= R_game; ++r) {
        log_metrics();
        int k = R_game - r + 1;

        int best_A = -1;
        bool can_force_win = dp[k][cur_mask][cur_p];

        if (can_force_win) {
            auto check_g = [&](int s) -> bool {
                if (s == 0) return true;
                for (int i=1; i<=9; ++i) {
                    if (has(cur_mask, i)) {
                        int nm = without_bit(cur_mask, i);
                        int np = expand_set(s, nm);
                        if (dp[k-1][nm][np]) return true;
                    }
                }
                return false;
            };
            for (int a = cur_p; ; a = (a-1) & cur_p) {
                if (check_g(a) && check_g(cur_p ^ a)) {
                    best_A = a;
                    break;
                }
                if (a == 0) break;
            }
        } else {
            int half_size = __builtin_popcount(cur_p) / 2;
            best_A = 0;
            for (int i=1; i<=9; ++i) {
                if (has(cur_p, i)) {
                    if (__builtin_popcount(best_A) < half_size) best_A = with_bit(best_A, i);
                }
            }
        }

        vector<int> q_list;
        for(int i=1; i<=9; ++i) if(has(best_A, i)) q_list.push_back(i);
        cout << q_list.size();
        for(int x : q_list) cout << " " << x;
        cout << endl;

        string ans;
        if (!(cin >> ans)) finish(_wa, "Unexpected EOF reading answer");
        int next_p_initial;
        if (ans == "Yes") next_p_initial = best_A;
        else if (ans == "No") next_p_initial = cur_p ^ best_A;
        else finish(_wa, "Invalid answer");

        int best_b = -1;

        for (int i=1; i<=9; ++i) {
            if (has(cur_mask, i)) {
                int nm = without_bit(cur_mask, i);
                int np = expand_set(next_p_initial, nm);
                if (dp[k-1][nm][np]) {
                    best_b = i;
                    break;
                }
            }
        }
        if (best_b == -1) {
            for(int i=1; i<=9; ++i) if(has(cur_mask, i)) { best_b = i; break; }
        }

        cout << best_b << endl;

        TrapHistory h;
        h.q_mask = best_A;
        h.ans = ans;
        h.b = best_b;
        hist.push_back(h);

        string res;
        if (!(cin >> res)) finish(_wa, "Unexpected EOF reading move result");

        if (res == "Trapped") finish(_wa, "Runner was trapped");
        else if (res == "Free") {
            cur_mask = without_bit(cur_mask, best_b);
            cur_p = expand_set(next_p_initial, cur_mask);
            queries = r;
        } else finish(_wa, "Invalid move result");
    }

    vector<int> path;
    for (int i=0; i <= R_game; ++i) {
        int x;
        if (!(cin >> x)) finish(_wa, "EOF reading proof");
        path.push_back(x);
    }

    int u = path[0];
    if (u < 1 || u > 9) finish(_wa, "Proof: Invalid start");
    for(int uv : unavailable_init) if(uv == u) finish(_wa, "Proof: Start unavailable");

    int check_mask = initial_mask;

    for (int r = 0; r < R_game; ++r) {
        bool in_q = has(hist[r].q_mask, u);
        if (hist[r].ans == "Yes" && !in_q) finish(_wa, "Proof inconsistent with answers");
        if (hist[r].ans == "No" && in_q) finish(_wa, "Proof inconsistent with answers");

        check_mask = without_bit(check_mask, hist[r].b);

        int v = path[r+1];
        if (v < 1 || v > 9) finish(_wa, "Proof: Invalid move square");
        if (!has(check_mask, v)) finish(_wa, "Proof: Move to unavailable square");

        bool adj_ok = false;
        for (int nxt : adj[u]) if (nxt == v) adj_ok = true;
        if (!adj_ok) finish(_wa, "Proof: Move not adjacent");

        u = v;
    }

    finish(_ok, "Correct");
}

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

    R_game = inf.readInt();
    U_game = inf.readInt();
    query_limit = R_game;

    int mask = 511;
    for (int i = 0; i < U_game; ++i) {
        int u = inf.readInt();
        unavailable_init.push_back(u);
        mask = without_bit(mask, u);
    }

    cout << R_game << " " << U_game << endl;
    if (U_game > 0) {
        for (int i = 0; i < U_game; ++i) {
            cout << unavailable_init[i] << (i == U_game - 1 ? "" : " ");
        }
        cout << endl;
    }

    init_adj();
    precompute_dp();

    bool trapper_wins_optimally = dp[R_game][mask][mask];

    string claim;
    if (!(cin >> claim)) finish(_wa, "No claim provided");

    bool contestant_is_runner = (claim == "Runner");
    bool contestant_is_trapper = (claim == "Trapper");

    if (!contestant_is_runner && !contestant_is_trapper)
        finish(_wa, "Invalid claim (expected Runner/Trapper)");

    if (contestant_is_runner) {
        play_as_trapper(mask);
    } else {
        play_as_runner(mask);
    }

    return 0;
}

#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

int R_total, U_total;
int S_initial_mask = 0;
vector<int> adj[10];

int8_t memo[10][512][512];

void init_adj() {

    auto add = [&](int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    };
    add(1, 2); add(2, 3);
    add(4, 5); add(5, 6);
    add(7, 8); add(8, 9);
    add(1, 4); add(4, 7);
    add(2, 5); add(5, 8);
    add(3, 6); add(6, 9);
}

int get_adj_mask(int u) {
    int m = 0;
    for (int v : adj[u]) m |= (1 << (v - 1));
    return m;
}

int next_p_mask(int P, int S_next) {
    int res = 0;
    for (int i = 0; i < 9; ++i) {
        if ((P >> i) & 1) {

            res |= get_adj_mask(i + 1);
        }
    }
    return res & S_next;
}

bool solve(int r, int S, int P);

bool can_trapper_win_after_answer(int r, int S, int P) {
    if (P == 0) return true;

    for (int i = 0; i < 9; ++i) {
        if ((S >> i) & 1) {
            int S_next = S & ~(1 << i);
            int P_next = next_p_mask(P, S_next);
            if (solve(r - 1, S_next, P_next)) return true;
        }
    }
    return false;
}

bool solve(int r, int S, int P) {
    if (P == 0) return true;
    if (r == 0) return false;

    if (memo[r][S][P] != -1) return memo[r][S][P];

    bool can_force_win = false;

    for (int A = P; ; A = (A - 1) & P) {
        if (can_trapper_win_after_answer(r, S, A)) {
            if (can_trapper_win_after_answer(r, S, P ^ A)) {
                can_force_win = true;
                break;
            }
        }
        if (A == 0) break;
    }

    return memo[r][S][P] = (can_force_win ? 1 : 0);
}

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

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

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

    init_adj();
    memset(memo, -1, sizeof(memo));

    R_total = inf.readInt();
    U_total = inf.readInt();
    S_initial_mask = (1 << 9) - 1;
    vector<int> unavailable;
    if (U_total > 0) {
        for (int i = 0; i < U_total; ++i) {
            int u = inf.readInt();
            unavailable.push_back(u);
            S_initial_mask &= ~(1 << (u - 1));
        }
    }

    query_limit = R_total;

    cout << R_total << " " << U_total << endl;
    if (U_total > 0) {
        for (int i = 0; i < U_total; ++i) {
            cout << unavailable[i] << (i == U_total - 1 ? "" : " ");
        }
        cout << endl;
    }
    cout.flush();

    string role;
    if (!(cin >> role)) finish(_pe, "No role output");

    string dummy; getline(cin, dummy);

    int current_S = S_initial_mask;
    int current_P = S_initial_mask;

    struct Turn {
        int Q_mask;
        bool ans_yes;
        int u;
    };
    vector<Turn> history_runner;

    if (role == "Runner") {

        for (int r = R_total; r >= 1; --r) {
            queries++;

            int best_A = -1;
            bool winning_split_found = false;

            if (solve(r, current_S, current_P)) {
                for (int A = current_P; ; A = (A - 1) & current_P) {
                    if (can_trapper_win_after_answer(r, current_S, A) &&
                        can_trapper_win_after_answer(r, current_S, current_P ^ A)) {
                        best_A = A;
                        winning_split_found = true;
                        break;
                    }
                    if (A == 0) break;
                }
            }

            if (!winning_split_found) {

                int min_diff = 100;
                for (int A = current_P; ; A = (A - 1) & current_P) {
                    int p1 = __builtin_popcount(A);
                    int p2 = __builtin_popcount(current_P ^ A);
                    if (abs(p1 - p2) < min_diff) {
                        min_diff = abs(p1 - p2);
                        best_A = A;
                    }
                    if (A == 0) break;
                }
            }

            vector<int> Q_vec;
            for(int i=0; i<9; ++i) if((best_A >> i) & 1) Q_vec.push_back(i+1);
            cout << Q_vec.size() << endl;
            if (!Q_vec.empty()) {
                for(size_t i=0; i<Q_vec.size(); ++i) cout << Q_vec[i] << (i==Q_vec.size()-1?"":" ");
                cout << endl;
            }
            cout.flush();

            string ans;
            if (!(cin >> ans)) finish(_pe, "Expected Yes/No");
            bool is_yes = (ans == "Yes");
            if (!is_yes && ans != "No") finish(_pe, "Invalid answer string");

            if (is_yes) current_P &= best_A;
            else current_P &= ~best_A;

            int best_u = -1;
            bool winning_u_found = false;

            for (int i=0; i<9; ++i) {
                if ((current_S >> i) & 1) {
                    int S_next = current_S & ~(1 << i);
                    int P_next = next_p_mask(current_P, S_next);
                    if (solve(r-1, S_next, P_next)) {
                        best_u = i+1;
                        winning_u_found = true;
                        break;
                    }
                }
            }

            if (!winning_u_found) {

                int min_sz = 100;
                for (int i=0; i<9; ++i) {
                    if ((current_S >> i) & 1) {
                        int S_next = current_S & ~(1 << i);
                        int P_next = next_p_mask(current_P, S_next);
                        int sz = __builtin_popcount(P_next);
                        if (sz < min_sz) {
                            min_sz = sz;
                            best_u = i+1;
                        }
                    }
                }
            }

            cout << best_u << endl;
            cout.flush();

            history_runner.push_back({best_A, is_yes, best_u});

            current_S &= ~(1 << (best_u - 1));
            current_P = next_p_mask(current_P, current_S);

            string status;
            if (!(cin >> status)) finish(_pe, "Expected Free/Trapped");

            if (status == "Trapped") {
                if (current_P == 0) finish(_wa, "Contestant claimed Runner but was trapped (correctly)");
                else finish(_wa, "Contestant claimed Runner but gave up (Trapped)");
            } else if (status != "Free") {
                finish(_pe, "Invalid status string");
            }
        }

        vector<int> proof(R_total + 1);
        for(int i=0; i<=R_total; ++i) {
            if (!(cin >> proof[i])) finish(_pe, "Expected proof integer");
        }

        int current_pos = proof[0];
        if (current_pos < 1 || current_pos > 9 || !((S_initial_mask >> (current_pos-1)) & 1))
            finish(_wa, "Proof: Invalid starting square");

        int avail_mask = S_initial_mask;
        for(int k=0; k<R_total; ++k) {

            bool in_Q = (history_runner[k].Q_mask >> (current_pos-1)) & 1;
            if (history_runner[k].ans_yes && !in_Q) finish(_wa, "Proof: Pos not in Query but answered Yes");
            if (!history_runner[k].ans_yes && in_Q) finish(_wa, "Proof: Pos in Query but answered No");

            int u = history_runner[k].u;
            avail_mask &= ~(1 << (u-1));

            int next_pos = proof[k+1];
            if (next_pos < 1 || next_pos > 9) finish(_wa, "Proof: Invalid square");
            if (!((avail_mask >> (next_pos-1)) & 1)) finish(_wa, "Proof: Move to unavailable square");

            bool adj_ok = false;
            for(int nb : adj[current_pos]) if(nb == next_pos) adj_ok = true;
            if (!adj_ok) finish(_wa, "Proof: Move not adjacent");

            current_pos = next_pos;
        }
        finish(_ok, "Survived and proved");

    } else if (role == "Trapper") {

        struct Step {
            int P_after_ans;
            int removed;
        };
        vector<Step> history;

        for (int r = R_total; r >= 1; --r) {
            queries++;

            int N;
            if (!(cin >> N)) finish(_pe, "Expected N");
            int Q_mask = 0;
            for(int i=0; i<N; ++i) {
                int x;
                if (!(cin >> x)) finish(_pe, "Expected x");
                Q_mask |= (1 << (x-1));
            }

            int P_yes = current_P & Q_mask;
            int P_no = current_P & ~Q_mask;

            string my_ans;

            bool win_yes = solve(r, current_S, P_yes);
            bool win_no = solve(r, current_S, P_no);

            if (!win_yes && !win_no) {
                if (__builtin_popcount(P_yes) >= __builtin_popcount(P_no)) my_ans = "Yes";
                else my_ans = "No";
            } else if (!win_yes) {
                my_ans = "Yes";
            } else if (!win_no) {
                my_ans = "No";
            } else {
                if (__builtin_popcount(P_yes) >= __builtin_popcount(P_no)) my_ans = "Yes";
                else my_ans = "No";
            }

            if (my_ans == "Yes") current_P = P_yes;
            else current_P = P_no;

            cout << my_ans << endl;
            cout.flush();

            int P_after_answer = current_P;

            int u;
            if (!(cin >> u)) finish(_pe, "Expected removal");
            current_S &= ~(1 << (u-1));

            current_P = next_p_mask(current_P, current_S);

            history.push_back({P_after_answer, u});

            if (current_P == 0) {
                cout << "Trapped" << endl;
                cout.flush();
                finish(_ok, "Interactor trapped (Contestant won)");
            } else {
                cout << "Free" << endl;
                cout.flush();
            }
        }

        vector<int> path(R_total + 1);
        int curr = -1;
        for(int i=0; i<9; ++i) if((current_P >> i) & 1) { curr = i+1; break; }
        path[R_total] = curr;

        for (int k = R_total - 1; k >= 0; --k) {
            int prev_P = history[k].P_after_ans;

            int found = -1;
            for(int i=0; i<9; ++i) {
                if ((prev_P >> i) & 1) {
                    int p = i+1;
                    for (int nb : adj[p]) if (nb == path[k+1]) found = p;
                }
            }
            path[k] = found;
        }

        for (int i=0; i<=R_total; ++i) cout << path[i] << (i==R_total?"":" ");
        cout << endl;
        finish(_wa, "Interactor survived (Contestant lost)");

    } else {
        finish(_pe, "Invalid role string");
    }

    return 0;
}

#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 seed_idx = -1;
    if (argc > 1) {
        try {
            seed_idx = stoi(argv[1]);
        } catch (...) {
            seed_idx = -1;
        }
    }

    int R, U;
    vector<int> unavailable;
    vector<int> grid(9);
    iota(grid.begin(), grid.end(), 1);

    if (seed_idx == 1) {

        R = 9;
        U = 0;
    } else if (seed_idx == 2) {

        R = 1;
        U = 8;
        shuffle(grid.begin(), grid.end());
        for (int i = 0; i < U; ++i) unavailable.push_back(grid[i]);
    } else if (seed_idx == 3) {

        U = 4;
        R = 5;
        unavailable = {2, 4, 6, 8};
    } else {

        U = rnd.next(0, 8);

        int max_R = 9 - U;
        if (rnd.next(3) == 0) {
            R = max_R;
        } else {
            R = rnd.next(1, max_R);
        }

        shuffle(grid.begin(), grid.end());
        for (int i = 0; i < U; ++i) {
            unavailable.push_back(grid[i]);
        }
    }

    sort(unavailable.begin(), unavailable.end());

    if (mode == "adp") {
        cout << R << " " << U << endl;
        if (U > 0) {
            for (int i = 0; i < U; ++i) {
                cout << unavailable[i] << (i == U - 1 ? "" : " ");
            }
            cout << endl;
        }
    } else {

        cout << R << " " << U << endl;
        if (U > 0) {
            for (int i = 0; i < U; ++i) {
                cout << unavailable[i] << (i == U - 1 ? "" : " ");
            }
            cout << endl;
        }
    }

    return 0;
}


As every Saturday, Eve is paying her local game club a visit. Today, Bob has brought a new game he has designed on his own. After thorough investigation, you claim that there exists a dominant strategy, so one player can always win. Bob is hesitant to accept that his game is boring to play, so he challenges you to play a round! Since you claim that there exists a dominant strategy, you may determine who begins the game.

![](images/6920571f0ae627b7ba9617f5be2e3e062a06b55a04aaae9ec604a876056045a5.jpg)
Figure E.1: The cards in the two sample interactions.

The rules are as follows. There are $n$ cards on the table, each containing a maths operation $( +$ or $\star ^ { \dagger }$ ) and an integer, as shown in Figure E.1. Eve and Bob alternate picking cards to manipulate a common number using one of the cards. For instance, if the current value of the number is 5, and the card says $+ 3$ , then the value gets updated to 8. Each card can only be used once, and the game ends when all the cards have been used. The player who makes the first move wins if the final number is odd, and the other player wins if the final number is even. Given the list of cards and the starting value, help Eve win the game.

# Interaction

The interactor begins by outputting the starting state of the game in the following format:

• One line with an integer $n$ $1 \leq n \leq 3 0 0 )$ , the number of cards.
• $n$ lines, each with a character $o$ and an integer $x$ $\zeta _ { O } \in \{ \cdot _ { + } , \cdot _ { \star } , \}$ , $1 \leq x \leq 1 0 ^ { 6 }$ ) indicating one of the cards.
• One line with an integer $x$ $( 1 \leq x \leq 1 0 ^ { 6 } )$ ), the starting value.

It is guaranteed that the $n$ cards in the input are distinct.

Then, your submission must output one of “me” or “you”, depending on if you want to go first or you want the interactor to go first.

Then your submission and the interactor alternate outputting cards in the same format as above. No card can be played more than once. Your submission must exit when all cards have been played, regardless of which player made the last move.

Your submission will be accepted if it follows all the rules above and the final value has the parity indicated on the first line of your output.

Make sure you flush the buffer after each write.

A testing tool is provided to help you develop your solution.

![](images/c2b2375e15f0f3183f4d2080ade82ec7b84cd0bb54ca7a6ed7b53f8ec77fcd26.jpg)

#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 << 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 Card {
    char op;
    int val;
    int type;
};

int get_type(char op, int val) {
    if (op == '+') {

        return (val % 2 != 0) ? 1 : 0;
    } else {

        return (val % 2 == 0) ? 2 : 0;
    }
}

int N;
int start_val;
int current_parity;
vector<Card> deck_z, deck_f, deck_i;
int initial_total;

int8_t memo[305][305][305];

int solve(int nz, int nf, int ni) {
    if (memo[nz][nf][ni] != -1) return memo[nz][nf][ni];

    int played = initial_total - (nz + nf + ni);
    int turn = played % 2;

    vector<int> outcomes;

    if (nz > 0) {
        if (nz == 1) {

            outcomes.push_back(nf % 2);
        } else {

            outcomes.push_back(solve(nz - 1, nf, ni));
        }
    }

    if (nf > 0) {
        outcomes.push_back(solve(nz, nf - 1, ni));
    }

    if (ni > 0) {
        outcomes.push_back(solve(nz, nf, ni - 1));
    }

    int res;
    if (turn == 0) {

        bool can_force_odd = false;
        for (int x : outcomes) if (x == 1) can_force_odd = true;
        res = can_force_odd ? 1 : 0;
    } else {

        bool can_force_even = false;
        for (int x : outcomes) if (x == 0) can_force_even = true;
        res = can_force_even ? 0 : 1;
    }

    return memo[nz][nf][ni] = res;
}

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

    N = inf.readInt(1, 300, "n");
    query_limit = N;
    initial_total = N;

    vector<Card> initial_cards;
    for (int i = 0; i < N; i++) {
        string ops = inf.readToken();
        int v = inf.readInt();
        char op = ops[0];
        int type = get_type(op, v);
        Card c = {op, v, type};
        initial_cards.push_back(c);

        if (type == 2) deck_z.push_back(c);
        else if (type == 1) deck_f.push_back(c);
        else deck_i.push_back(c);
    }
    start_val = inf.readInt();
    current_parity = start_val % 2;

    cout << N << endl;
    for (const auto& c : initial_cards) {
        cout << c.op << " " << c.val << endl;
    }
    cout << start_val << endl;
    cout.flush();

    string role;
    if (!(cin >> role)) finish(_wa, "Unexpected EOF reading role");

    if (role == "?") cin >> role;

    bool contestant_is_p1;
    if (role == "me") contestant_is_p1 = true;
    else if (role == "you") contestant_is_p1 = false;
    else finish(_pe, "Expected 'me' or 'you', got: " + role);

    memset(memo, -1, sizeof(memo));

    for (int k = 0; k < N; k++) {

        bool is_p1_turn = (k % 2 == 0);
        bool is_contestant_turn = (is_p1_turn == contestant_is_p1);

        if (is_contestant_turn) {
            queries++;

            string op_str;
            if (!(cin >> op_str)) finish(_wa, "Unexpected EOF waiting for move");

            if (op_str == "!") finish(_pe, "Unexpected '!' during game");
            if (op_str == "?") {
                if (!(cin >> op_str)) finish(_wa, "Unexpected EOF after '?'");
            }

            if (op_str.size() != 1 || (op_str[0] != '+' && op_str[0] != '*')) {
                finish(_pe, "Invalid operator token: " + op_str);
            }
            char op = op_str[0];
            int val;
            if (!(cin >> val)) finish(_wa, "Unexpected EOF reading value");

            int type = get_type(op, val);
            vector<Card>* deck = nullptr;
            if (type == 2) deck = &deck_z;
            else if (type == 1) deck = &deck_f;
            else deck = &deck_i;

            int found_idx = -1;
            for (int i = 0; i < (int)deck->size(); i++) {
                if ((*deck)[i].op == op && (*deck)[i].val == val) {
                    found_idx = i;
                    break;
                }
            }

            if (found_idx == -1) {
                finish(_wa, "Card not available or already played: " + string(1, op) + " " + to_string(val));
            }

            if (type == 1) current_parity = (current_parity + 1) % 2;
            else if (type == 2) current_parity = 0;

            deck->erase(deck->begin() + found_idx);

        } else {

            Card pick;
            bool picked = false;

            if (deck_z.empty()) {
                if (!deck_f.empty()) { pick = deck_f[0]; deck_f.erase(deck_f.begin()); }
                else if (!deck_i.empty()) { pick = deck_i[0]; deck_i.erase(deck_i.begin()); }
                else {  }
                picked = true;
            } else {

                int nz = deck_z.size();
                int nf = deck_f.size();
                int ni = deck_i.size();
                int want = is_p1_turn ? 1 : 0;

                if (!picked && nz > 0) {
                    int outcome = (nz == 1) ? (nf % 2) : solve(nz - 1, nf, ni);
                    if (outcome == want) {
                        pick = deck_z[0]; deck_z.erase(deck_z.begin());
                        picked = true;
                    }
                }

                if (!picked && nf > 0) {
                    int outcome = solve(nz, nf - 1, ni);
                    if (outcome == want) {
                        pick = deck_f[0]; deck_f.erase(deck_f.begin());
                        picked = true;
                    }
                }

                if (!picked && ni > 0) {
                    int outcome = solve(nz, nf, ni - 1);
                    if (outcome == want) {
                        pick = deck_i[0]; deck_i.erase(deck_i.begin());
                        picked = true;
                    }
                }

                if (!picked) {
                    if (!deck_z.empty()) { pick = deck_z[0]; deck_z.erase(deck_z.begin()); }
                    else if (!deck_f.empty()) { pick = deck_f[0]; deck_f.erase(deck_f.begin()); }
                    else { pick = deck_i[0]; deck_i.erase(deck_i.begin()); }
                }
            }

            if (pick.type == 1) current_parity = (current_parity + 1) % 2;
            else if (pick.type == 2) current_parity = 0;

            cout << pick.op << " " << pick.val << endl;
            cout.flush();
        }

        if ((k + 1) % 10 == 0) log_metrics();
    }

    bool p1_wins = (current_parity == 1);

    bool contestant_wins = (contestant_is_p1 && p1_wins) || (!contestant_is_p1 && !p1_wins);

    if (contestant_wins) {
        finish(_ok, "Contestant won the game.");
    } else {
        finish(_wa, "Contestant lost the game.");
    }

    return 0;
}

#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;

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

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

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

struct Card {
    char op;
    int val;
    int id;

    int type() const {
        if (op == '*') {
            if (val % 2 == 0) return 2;
            else return 0;
        } else {
            if (val % 2 != 0) return 1;
            else return 0;
        }
    }

    string toString() const {
        return string(1, op) + " " + to_string(val);
    }
};

int N_cards;
int Start_Val;
vector<Card> all_cards;
vector<Card*> setters, flippers, identities;

int memo[301][301][301][2];

int get_goal(int p_idx) {
    return (p_idx == 0) ? 1 : 0;
}

int solve(int k, int m, int z, int p) {

    if (k == 0) return 0;

    if (memo[k][m][z][p] != -1) return memo[k][m][z][p];

    int my_goal = get_goal(p);
    bool can_force_win = false;

    {
        if (k == 1) {

            int outcome = m % 2;
            if (outcome == my_goal) can_force_win = true;
        } else {

            if (!solve(k - 1, m, z, 1 - p)) can_force_win = true;
        }
    }

    if (!can_force_win && m > 0) {
        if (!solve(k, m - 1, z, 1 - p)) can_force_win = true;
    }

    if (!can_force_win && z > 0) {
        if (!solve(k, m, z - 1, 1 - p)) can_force_win = true;
    }

    return memo[k][m][z][p] = (can_force_win ? 1 : 0);
}

int get_best_move(int k, int m, int z, int p) {

    bool setter_wins = false;
    if (k == 1) {
        if ((m % 2) == get_goal(p)) setter_wins = true;
    } else if (k > 1) {
        if (!solve(k - 1, m, z, 1 - p)) setter_wins = true;
    }
    if (setter_wins) return 2;

    if (m > 0) {
        if (!solve(k, m - 1, z, 1 - p)) return 1;
    }

    if (z > 0) {
        if (!solve(k, m, z - 1, 1 - p)) return 0;
    }

    if (k > 0) return 2;
    if (m > 0) return 1;
    return 0;
}

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

    N_cards = inf.readInt();
    query_limit = N_cards;

    for (int i = 0; i < N_cards; i++) {
        string token = inf.readToken();
        int val = inf.readInt();
        char op = token[0];
        all_cards.push_back({op, val, i});
    }
    Start_Val = inf.readInt();

    cout << N_cards << endl;
    for (const auto& c : all_cards) {
        cout << c.toString() << endl;
    }
    cout << Start_Val << endl;
    cout.flush();

    log_metrics();

    for (int i = 0; i < N_cards; i++) {
        int t = all_cards[i].type();
        if (t == 2) setters.push_back(&all_cards[i]);
        else if (t == 1) flippers.push_back(&all_cards[i]);
        else identities.push_back(&all_cards[i]);
    }

    int K = setters.size();
    int M = flippers.size();
    int Z = identities.size();

    string side;
    if (!(cin >> side)) finish(_pe, "No side output");

    int my_role = -1;
    int con_role = -1;

    if (side == "me") {

        con_role = 0;
        my_role = 1;
    } else if (side == "you") {

        con_role = 1;
        my_role = 0;
    } else {
        finish(_pe, "Invalid side: " + side);
    }

    memset(memo, -1, sizeof(memo));

    vector<bool> used(N_cards, false);
    int turn = 0;
    int current_parity = (Start_Val % 2);

    for (int move_num = 0; move_num < N_cards; move_num++) {
        queries = move_num + 1;
        Card* pick = nullptr;

        if (turn == my_role) {

            if (K == 0) {

                if (!setters.empty()) { pick = setters.back(); setters.pop_back(); }
                else if (!flippers.empty()) { pick = flippers.back(); flippers.pop_back(); }
                else { pick = identities.back(); identities.pop_back(); }
            } else {

                int type = get_best_move(K, M, Z, my_role);
                if (type == 2) { pick = setters.back(); setters.pop_back(); K--; }
                else if (type == 1) { pick = flippers.back(); flippers.pop_back(); M--; }
                else { pick = identities.back(); identities.pop_back(); Z--; }
            }

            if (!pick) finish(_pe, "Interactor internal error: no card to play");

            used[pick->id] = true;
            cout << pick->toString() << endl;

            if (pick->op == '+') current_parity = (current_parity + pick->val) % 2;
            else current_parity = (current_parity * pick->val) % 2;

        } else {

            string op_str;
            if (!(cin >> op_str)) finish(_pe, "Unexpected EOF waiting for card op");
            int val;
            if (!(cin >> val)) finish(_pe, "Unexpected EOF waiting for card val");

            char op = op_str[0];

            int found_idx = -1;
            for (int i = 0; i < N_cards; i++) {
                if (!used[i] && all_cards[i].op == op && all_cards[i].val == val) {
                    found_idx = i;
                    break;
                }
            }

            if (found_idx == -1) {
                finish(_wa, "Played invalid or used card: " + op_str + " " + to_string(val));
            }

            used[found_idx] = true;
            pick = &all_cards[found_idx];

            int t = pick->type();
            auto remove_from = [&](vector<Card*>& vec) {
                for (auto it = vec.begin(); it != vec.end(); ++it) {
                    if ((*it)->id == found_idx) {
                        vec.erase(it);
                        return;
                    }
                }
            };

            if (t == 2) { K--; remove_from(setters); }
            else if (t == 1) { M--; remove_from(flippers); }
            else { Z--; remove_from(identities); }

            if (pick->op == '+') current_parity = (current_parity + pick->val) % 2;
            else current_parity = (current_parity * pick->val) % 2;
        }

        turn = 1 - turn;
    }

    int needed_parity = get_goal(con_role);
    if (current_parity == needed_parity) {
        finish(_ok, "Contestant won (Parity " + to_string(current_parity) + ")");
    } else {
        finish(_wa, "Contestant lost (Parity " + to_string(current_parity) + ", expected " + to_string(needed_parity) + ")");
    }

    return 0;
}

#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 seed_idx = atoi(argv[1]);

    int n;
    int start_val;
    vector<pair<char, int>> cards;
    set<pair<char, int>> distinct_check;

    auto try_add = [&](char op, int val) {
        if (distinct_check.count({op, val})) return false;
        distinct_check.insert({op, val});
        cards.push_back({op, val});
        return true;
    };

    if (seed_idx == 1) {

        n = 1;
        start_val = 1;
        try_add('+', 1);
    } else if (seed_idx == 2) {

        n = 300;
        start_val = 2;
        for (int i = 0; i < n; i++) {
            while(!try_add('+', rnd.next(1, 500000) * 2));
        }
    } else if (seed_idx == 3) {

        n = 300;
        start_val = 3;
        for (int i = 0; i < n; i++) {

            while(!try_add('*', rnd.next(1, 500000) * 2));
        }
    } else {

        if (rnd.next(1, 10) == 1) {

            n = rnd.next(1, 50);
        } else {

            n = rnd.next(200, 300);
        }

        start_val = rnd.next(1, 1000000);

        int strat = rnd.next(0, 3);

        if (mode == "adp" && strat == 0) strat = rnd.next(1, 3);

        for (int i = 0; i < n; i++) {
            int attempts = 0;
            while (true) {
                char op;
                int val;

                if (strat == 1) op = rnd.next(1, 10) > 2 ? '*' : '+';
                else if (strat == 2) op = rnd.next(1, 10) > 2 ? '+' : '*';
                else op = rnd.next(0, 1) ? '+' : '*';

                val = rnd.next(1, 1000000);

                if (strat == 3) {

                    if (op == '+' && rnd.next(0, 1)) {
                        val = rnd.next(1, 500000) * 2 - 1;
                    }

                    if (op == '*' && rnd.next(0, 1)) {
                        val = rnd.next(1, 500000) * 2;
                    }
                }

                if (try_add(op, val)) break;

                attempts++;
                if (attempts > 50) {

                    op = rnd.next(0, 1) ? '+' : '*';
                    val = rnd.next(1, 1000000);
                    if (try_add(op, val)) break;
                }
            }
        }
    }

    println(n);
    for (const auto& p : cards) {
        println(p.first, p.second);
    }
    println(start_val);

    return 0;
}