Problem: cf1137_d
Difficulty: medium
Categories: graph, math
Time limit: 1000 ms, memory limit: 512 MB

This is an interactive problem.

Misha likes to play cooperative games with incomplete information. Today he suggested ten his friends to play a cooperative game "Lake".

Misha has already come up with a field for the upcoming game. The field for this game is a directed graph consisting of two parts. The first part is a road along the coast of the lake which is a cycle of $c$ vertices. The second part is a path from home to the lake which is a chain of $t$ vertices, and there is an edge from the last vertex of this chain to the vertex of the road along the coast which has the most beautiful view of the lake, also known as the finish vertex. Misha decided to keep the field secret, so nobody knows neither $t$ nor $c$.

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

Note that each vertex of the field has exactly one outgoing edge and all the vertices except the home vertex and the finish vertex have exactly one ingoing edge. The home vertex has no incoming edges, the finish vertex has two incoming edges.

At the beginning of the game pieces of all the ten players, indexed with consecutive integers from $0$ to $9$, are at the home vertex. After that on each turn some of the players can ask Misha to simultaneously move their pieces along the corresponding edges. Misha will not answer more than $q$ such queries. After each move Misha will tell players whose pieces are at the same vertices and whose pieces are at different vertices.

The goal of the game is to move all the pieces to the finish vertex. Misha's friends have no idea how to win in such a game without knowledge of $c$, $t$ and $q$, but luckily they are your friends. Help them: coordinate their actions to win the game.

Misha has drawn such a field that $1 \le t, c$, $(t+c) \leq 1000$ and $q = 3 \cdot (t+c)$.

Input

There is no input — go to the interaction part straight away.

Output

After all friends gather at the finish vertex, print "done" and terminate your program.

Interaction

To give a command to move the friends, print "next" and then space-separated indices of the friends you want to move. For example, to give the command to move the friends with indices $0$, $2$, $5$ and $9$ print "next 0 2 5 9". At each turn, you must move at least one of your friends.

As an answer, first read an integer $k$, and then $10$ digits divided into $k$ space-separated groups. The friends that correspond to the indices in the same group are in the same vertex. The friends that correspond to indices in different groups are in different vertices. The indices in each group follow in ascending order.

For example, the answer "2 05 12346789" means that the friends with indices $0$ and $5$ are in one vertex, and all other friends are in the same but different vertex. The answer "4 01 567 234 89" means that Misha's friends are in four different vertices: the friends with indices $0$ and $1$ are in the first, the friends with indices $5$, $6$ and $7$ are in the second, the friends with indices $2$, $3$ and $4$ are in the third, and the friends with indices $8$ and $9$ are in the fourth.

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.

Answer "stop" instead of a valid one means that you made an invalid query. Exit immediately after receiving "stop" 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.

Example

Input

```
2 05 12346789

3 246789 135 0

3 246789 0 135

3 246789 0 135

2 135 0246789

1 0123456789
```

Output

```
next 0 5

next 0 1 3

next 2 3 0 1 4 5 6 7 8 9

next 9 8 7 6 5 4 3 2 1 0

next 0 1 3 5

next 1 3 5

done
```

Note

In the sample input and output values are aligned only for simplicity of interpreting them chronologically. In real interaction no "extra" line breaks should appear.

In the example, the friends move as follows:

 ![](https://espresso.codeforces.com/5e7369269b460f4d6497aee10638d37077d49e30.png)

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 << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}

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

static bool isAllDigits(const string& s) {
    if (s.empty()) return false;
    for (char ch : s) if (ch < '0' || ch > '9') return false;
    return true;
}

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

    int t = inf.readInt(1, 1000, "t");
    int c = inf.readInt(1, 1000, "c");
    ensuref(t + c <= 1000, "t+c must be <= 1000");

    query_limit = 3LL * (t + c);
    log_metrics(); 

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

    const int finishVertex = t;
    const int cycleStart = t;
    const int cycleLen = c;

    vector<int> pos(10, 0);

    auto nextVertex = [&](int v) -> int {
        if (v < t - 1) return v + 1;          
        if (v == t - 1) return finishVertex;  
        
        int k = v - cycleStart;
        k = (k + 1) % cycleLen;
        return cycleStart + k;
    };

    auto allAtFinish = [&]() -> bool {
        for (int i = 0; i < 10; i++) if (pos[i] != finishVertex) return false;
        return true;
    };

    auto replyPartition = [&]() {
        map<int, vector<int>> groupsByVertex;
        for (int i = 0; i < 10; i++) groupsByVertex[pos[i]].push_back(i);

        cout << (int)groupsByVertex.size();
        for (auto& [v, ids] : groupsByVertex) {
            sort(ids.begin(), ids.end());
            string grp;
            grp.reserve(ids.size());
            for (int id : ids) grp.push_back(char('0' + id));
            cout << " " << grp;
        }
        cout << endl; 
    };

    string line;
    while (true) {
        if (!std::getline(cin, line)) {
            finish(_pe, "Unexpected EOF from contestant");
        }
        
        bool anyNonSpace = false;
        for (char ch : line) if (!isspace((unsigned char)ch)) { anyNonSpace = true; break; }
        if (!anyNonSpace) continue;

        stringstream ss(line);
        string cmd;
        ss >> cmd;
        if (cmd == "done") {
            string extra;
            if (ss >> extra) {
                cout << "stop" << endl;
                finish(_wa, "Extra tokens after 'done'");
            }
            if (allAtFinish()) finish(_ok, "OK");
            finish(_wa, "Printed 'done' before all pieces reached finish vertex");
        }

        if (cmd != "next") {
            cout << "stop" << endl;
            finish(_wa, "Unknown command (expected 'next' or 'done')");
        }

        vector<int> movers;
        string tok;
        while (ss >> tok) {
            if (!isAllDigits(tok)) {
                cout << "stop" << endl;
                finish(_wa, "Invalid token in 'next' command");
            }
            long long v = 0;
            for (char ch : tok) {
                v = v * 10 + (ch - '0');
                if (v > 1000000) break;
            }
            if (v < 0 || v > 9) {
                cout << "stop" << endl;
                finish(_wa, "Moved index out of range (0..9)");
            }
            movers.push_back((int)v);
        }

        if (movers.empty()) {
            cout << "stop" << endl;
            finish(_wa, "Must move at least one friend");
        }

        {
            bool seen[10] = {false};
            for (int x : movers) {
                if (seen[x]) {
                    cout << "stop" << endl;
                    finish(_wa, "Duplicate index in one query");
                }
                seen[x] = true;
            }
        }

        queries++;
        log_metrics(); 
        if (queries > hard_cap) {
            finish(_pe, "Hard cap exceeded (possible infinite loop / spam)");
        }

        for (int x : movers) pos[x] = nextVertex(pos[x]);

        replyPartition();
    }
}


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 int N_total = 0;                 
static vector<int> feasible_t;          
static array<long long, 10> moves_cnt;  

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 vector<string> split_tokens(const string& s) {
    vector<string> toks;
    string cur;
    for (char ch : s) {
        if (isspace((unsigned char)ch)) {
            if (!cur.empty()) {
                toks.push_back(cur);
                cur.clear();
            }
        } else {
            cur.push_back(ch);
        }
    }
    if (!cur.empty()) toks.push_back(cur);
    return toks;
}

static inline int vertex_key_for(int t, int c, long long mv) {
    if (mv < t) return (int)mv; 
    long long r = mv - t;
    int cyc = (int)(r % c);     
    return t + cyc;             
}

static inline bool is_finish_for(int t, int c, long long mv) {
    if (mv < t) return false;
    return ((mv - t) % c) == 0;
}



static uint64_t signature_code_for_t(int t) {
    int c = N_total - t;
    int keys[10];
    for (int i = 0; i < 10; i++) keys[i] = vertex_key_for(t, c, moves_cnt[i]);

    int gid[10];
    for (int i = 0; i < 10; i++) gid[i] = -1;

    int k = 0;
    for (int i = 0; i < 10; i++) {
        if (gid[i] != -1) continue;
        int mykey = keys[i];
        for (int j = i; j < 10; j++) {
            if (gid[j] == -1 && keys[j] == mykey) gid[j] = k;
        }
        k++;
    }

    uint64_t code = (uint64_t)k;
    for (int i = 0; i < 10; i++) {
        code |= (uint64_t)gid[i] << (4 * (i + 1));
    }
    return code;
}

static vector<string> build_groups_for_t(int t) {
    int c = N_total - t;
    int keys[10];
    for (int i = 0; i < 10; i++) keys[i] = vertex_key_for(t, c, moves_cnt[i]);

    int gid[10];
    for (int i = 0; i < 10; i++) gid[i] = -1;

    vector<vector<int>> groups;
    for (int i = 0; i < 10; i++) {
        if (gid[i] != -1) continue;
        int mykey = keys[i];
        vector<int> g;
        for (int j = i; j < 10; j++) {
            if (gid[j] == -1 && keys[j] == mykey) {
                gid[j] = (int)groups.size();
                g.push_back(j);
            }
        }
        groups.push_back(std::move(g));
    }

    vector<string> out;
    out.reserve(groups.size());
    for (auto& g : groups) {
        sort(g.begin(), g.end());
        string s;
        s.reserve(g.size());
        for (int idx : g) s.push_back(char('0' + idx));
        out.push_back(s);
    }
    return out;
}

static void send_partition_reply(int t) {
    vector<string> groups = build_groups_for_t(t);
    cout << (int)groups.size();
    for (const string& g : groups) cout << " " << g;
    cout << endl;
}

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

    moves_cnt.fill(0);

    
    
    
    int a = inf.readInt(1, 1000, "a");
    if (!inf.seekEof()) {
        int b = inf.readInt(1, 1000, "b");
        inf.readEof();
        int t = a, c = b;
        ensuref(t + c >= 2 && t + c <= 1000, "t+c out of range");
        N_total = t + c;
        query_limit = 3LL * N_total;
        feasible_t.clear();
        feasible_t.push_back(t);
    } else {
        int maxN = a;
        ensuref(maxN >= 2 && maxN <= 1000, "maxN out of range");
        N_total = maxN; 
        query_limit = 3LL * N_total;
        feasible_t.clear();
        feasible_t.reserve(max(0, N_total - 1));
        for (int t = 1; t <= N_total - 1; t++) feasible_t.push_back(t);
    }

    
    log_metrics();

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

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

        if (cmd == "done") {
            if (feasible_t.empty()) finish(_pe, "internal: empty feasible set at done");

            for (int t : feasible_t) {
                int c = N_total - t;
                bool all_ok = true;
                for (int i = 0; i < 10; i++) {
                    if (!is_finish_for(t, c, moves_cnt[i])) {
                        all_ok = false;
                        break;
                    }
                }
                if (!all_ok) finish(_wa, "done claimed but not guaranteed");
            }
            finish(_ok, "ok");
        }

        if (cmd != "next") {
            cout << "stop" << endl;
            finish(_wa, "unknown command");
        }

        string rest;
        getline(cin, rest); 
        vector<string> toks = split_tokens(rest);

        if (toks.empty()) {
            cout << "stop" << endl;
            finish(_wa, "empty move set");
        }

        bool used[10];
        memset(used, 0, sizeof(used));
        vector<int> idx;
        idx.reserve(toks.size());

        for (const string& tok : toks) {
            if (tok.size() != 1 || tok[0] < '0' || tok[0] > '9') {
                cout << "stop" << endl;
                finish(_wa, "invalid index token");
            }
            int v = tok[0] - '0';
            if (used[v]) {
                cout << "stop" << endl;
                finish(_wa, "duplicate index");
            }
            used[v] = true;
            idx.push_back(v);
        }

        
        for (int v : idx) moves_cnt[v]++;

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

        if (feasible_t.empty()) finish(_pe, "internal: empty feasible set before reply");

        
        map<uint64_t, pair<int, int>> info; 
        for (int t : feasible_t) {
            uint64_t code = signature_code_for_t(t);
            auto& entry = info[code];
            entry.first++;
            if (entry.second == 0) entry.second = t;
            else entry.second = min(entry.second, t);
        }

        int bestCount = -1;
        uint64_t bestCode = 0;
        int bestRepT = -1;

        for (const auto& it : info) {
            uint64_t code = it.first;
            int cnt = it.second.first;
            int repT = it.second.second;
            if (cnt > bestCount || (cnt == bestCount && code < bestCode)) {
                bestCount = cnt;
                bestCode = code;
                bestRepT = repT;
            }
        }

        if (bestRepT < 1) finish(_pe, "internal: failed to choose reply");

        
        vector<int> next_feasible;
        next_feasible.reserve(feasible_t.size());
        for (int t : feasible_t) {
            if (signature_code_for_t(t) == bestCode) next_feasible.push_back(t);
        }
        feasible_t.swap(next_feasible);

        if (feasible_t.empty()) finish(_pe, "internal: reply made feasible set empty");

        send_partition_reply(bestRepT);
    }
}


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

static bool isPrimeInt(int x) {
    if (x < 2) return false;
    for (int d = 2; d * d <= x; d++) {
        if (x % d == 0) return false;
    }
    return true;
}

static int nearestPrimeClamped(int target, int lo, int hi) {
    target = max(lo, min(hi, target));
    if (isPrimeInt(target)) return target;
    for (int delta = 1; delta <= hi - lo; delta++) {
        int a = target - delta;
        if (a >= lo && isPrimeInt(a)) return a;
        int b = target + delta;
        if (b <= hi && isPrimeInt(b)) return b;
    }
    for (int x = lo; x <= hi; x++) if (isPrimeInt(x)) return x;
    return lo;
}

static long long parseSeedFromArgv(int argc, char** argv) {
    if (argc < 2) return 1;
    string s = argv[1];
    bool neg = false;
    int i = 0;
    if (!s.empty() && (s[0] == '-' || s[0] == '+')) {
        neg = (s[0] == '-');
        i = 1;
    }
    long long v = 0;
    for (; i < (int)s.size(); i++) {
        if (s[i] < '0' || s[i] > '9') break;
        v = v * 10 + (s[i] - '0');
        if (v > (long long)4e18) break;
    }
    return neg ? -v : v;
}

int main(int argc, char** argv) {
    registerGen(argc, argv, 1);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    string mode = opt<string>("mode", "non");
    long long seed = parseSeedFromArgv(argc, argv);

    if (mode == "non") {
        int forcedT = opt<int>("t", -1);
        int forcedC = opt<int>("c", -1);
        int forcedN = opt<int>("n", -1);

        int t = -1, c = -1;

        if (seed == 1) {
            t = 1; c = 1;
        } else if (seed == 2) {
            t = 999; c = 1;
        } else if (seed == 3) {
            t = 1; c = 999;
        } else if (forcedT >= 1 && forcedC >= 1 && forcedT + forcedC <= 1000) {
            t = forcedT;
            c = forcedC;
        } else {
            int n;
            if (forcedN >= 2 && forcedN <= 1000) n = forcedN;
            else n = rnd.next(950, 1000);

            int kind = rnd.next(0, 5);
            if (kind == 0) {
                int target = n / 2 + rnd.next(-25, 25);
                c = nearestPrimeClamped(target, 1, n - 1);
            } else if (kind == 1) {
                int target = (2 * n) / 3 + rnd.next(-25, 25);
                c = nearestPrimeClamped(target, 1, n - 1);
            } else if (kind == 2) {
                int target = n - 3 - rnd.next(0, 10);
                c = nearestPrimeClamped(target, 1, n - 1);
            } else if (kind == 3) {
                static const int hardCycles[] = {511, 513, 255, 257, 127, 129, 63, 65, 999, 997, 991, 983};
                int pick = hardCycles[rnd.next(0, (int)(sizeof(hardCycles) / sizeof(hardCycles[0])) - 1)];
                c = max(1, min(n - 1, pick));
                if (c == n) c = n - 1;
            } else {
                c = rnd.next(1, n - 1);
            }

            t = n - c;
            if (t < 1) { t = 1; c = n - 1; }
            if (c < 1) { c = 1; t = n - 1; }

            if (!isPrimeInt(c) && rnd.next(0, 1) == 1) {
                int c2 = nearestPrimeClamped(c, 1, n - 1);
                if (c2 >= 1 && c2 <= n - 1) {
                    c = c2;
                    t = n - c;
                    if (t < 1) { t = 1; c = n - 1; }
                }
            }
        }

        if (t < 1) t = 1;
        if (c < 1) c = 1;
        if (t + c > 1000) {
            int n = 1000;
            if (t >= n) t = n - 1;
            c = n - t;
            if (c < 1) { c = 1; t = n - 1; }
        }

        cout << t << " " << c << "\n";
        return 0;
    }

    if (mode == "adp") {
        int maxN = opt<int>("n", 1000);

        if (seed == 1) maxN = 2;
        else if (seed == 2) maxN = 1000;
        else if (seed == 3) maxN = 17;
        else maxN = max(2, min(1000, maxN));

        cout << maxN << "\n";
        return 0;
    }

    quitf(_fail, "unknown --mode (expected non/adp)");
    return 0;
}