Problem: cf1147_e
Difficulty: hard
Categories: math
Time limit: 6000 ms, memory limit: 256 MB

Carl has $n$ coins of various colors, and he would like to sort them into piles. The coins are labeled $1,2,\ldots,n$, and each coin is exactly one of red, green, or blue. He would like to sort the coins into three different piles so one pile contains all red coins, one pile contains all green coins, and one pile contains all blue coins.

Unfortunately, Carl is colorblind, so this task is impossible for him. Luckily, he has a friend who can take a pair of coins and tell Carl if they are the same color or not. Using his friend, Carl believes he can now sort the coins. The order of the piles doesn't matter, as long as all same colored coins are in the one pile, and no two different colored coins are in the same pile.

His friend will answer questions about multiple pairs of coins in batches, and will answer about all of those pairs in parallel. Each coin should be in at most one pair in each batch. The same coin can appear in different batches.

Carl can use only $7$ batches. Help him find the piles of coins after sorting.

Interaction

You will be given multiple test cases. The first line contains an integer $t$ $(1 \leq t \leq 5$) — the number of test cases.

The first line of each test case contains one integer $n$ ($1 \leq n \leq 10^5$) — the number of coins. If you read in a value of $-1$ here, that means that you printed an invalid answer in the previous case and exit immediately to avoid getting other verdicts.

To ask a question, print "Q $k\ x_1\ y_1\ \ldots\ x_k\ y_k$" ($1 \leq k \leq n/2, 1 \leq x_i,y_i \leq n, x_i \neq y_i$). $k$ denotes the number of pairs in the batch, and $x_i, y_i$ denote the $i$-th pair of coins in the batch. A coin can only appear at most once in a batch. All $x_i$ and $y_i$ should be distinct.

The judge will respond with a bitstring of length $k$, where the $i$-th character is "1" if $x_i$ and $y_i$ are the same color, and "0" otherwise. The judge will respond with $-1$ if you ever ask an invalid query. Make sure to exit immediately to avoid getting other verdicts.

When you are ready to answer, print four lines.

The first line contains "A $k_1\ k_2\ k_3$" ($0 \leq k_1,k_2,k_3$ and $k_1+k_2+k_3 = n$). These denote the sizes of the three piles.

The next line has $k_1$ integers, the labels of the coins in the first pile.

The next line has $k_2$ integers, the labels of the coins in the second pile.

The next line has $k_3$ integers, the labels coins in the third pile.

Each coin must appear in exactly one pile.

You may only ask at most $7$ batches per test case.

After printing a query and the answer 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

```
3
3
1
1
1
3
1
0
0
6
000
010
100
001
000
```

Output

```
Q 1 1 2
Q 1 2 3
Q 1 1 3
A 3 0 0
1 2 3

Q 1 1 3
Q 1 2 3
Q 1 1 2
A 2 0 1
1 3

2
Q 3 1 2 3 4 5 6
Q 3 1 3 2 5 4 6
Q 3 1 4 2 6 3 5
Q 3 1 5 2 4 3 6
Q 3 1 6 2 3 4 5
A 2 2 2
1 4
2 5
3 6
```

Note

In the example, there are three test cases.

In the first test case, there are three coins. We ask about the pairs $(1,2)$, $(2,3)$, and $(1,3)$ in different batches and get that they are all the same color. Thus, we know all the coins are the same color, so we can put them all in one pile. Note that some piles can be empty and those are denoted with an empty line.

In the second test case, there are three coins again. This time, we only get that $(1,3)$ are the same and $(1,2)$ and $(2,3)$ are different. So, one possible scenario is that coins $1$ and $3$ are red and coin $2$ is green.

In the last case, there are $6$ coins. The case shows how to ask and receive answers for multiple pairs in one batch.

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

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

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

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

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

static bool parseLongLongStrict(const string& s, long long& out) {
    if (s.empty()) return false;
    int i = 0;
    bool neg = false;
    if (s[i] == '+' || s[i] == '-') {
        neg = (s[i] == '-');
        i++;
    }
    if (i >= (int)s.size()) return false;
    long long val = 0;
    for (; i < (int)s.size(); i++) {
        char c = s[i];
        if (c < '0' || c > '9') return false;
        int d = c - '0';
        if (val > (LLONG_MAX - d) / 10) return false;
        val = val * 10 + d;
    }
    out = neg ? -val : val;
    return true;
}

static long long readLLOrPE(const string& what) {
    string tok;
    if (!readTokenFromContestant(tok)) finish(_pe, "Unexpected EOF while reading " + what);
    long long x;
    if (!parseLongLongStrict(tok, x)) finish(_pe, "Malformed integer for " + what);
    return x;
}

static void printToContestantLine(const string& s) {
    cout << s << "\n";
    cout.flush();
}

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

    try {
        int t = inf.readInt(1, 5, "t");

        struct CaseData {
            int n;
            string colors; 
        };
        vector<CaseData> cases;
        cases.reserve(t);

        for (int tc = 0; tc < t; tc++) {
            int n = inf.readInt(1, 100000, "n");
            string colors = inf.readToken();
            if ((int)colors.size() != n) finish(_pe, "Hidden colors length mismatch");
            for (char c : colors) {
                if (c != 'R' && c != 'G' && c != 'B') finish(_pe, "Hidden colors contain invalid character");
            }
            cases.push_back({n, colors});
        }

        query_limit = 7LL * t;
        log_metrics(); 

        {
            ostringstream os;
            os << t;
            printToContestantLine(os.str());
        }

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

        for (int tc = 0; tc < t; tc++) {
            const int n = cases[tc].n;
            const string& col = cases[tc].colors;

            {
                ostringstream os;
                os << n;
                printToContestantLine(os.str());
            }

            bool answered = false;
            while (!answered) {
                if (queries > hard_cap) finish(_pe, "Hard cap exceeded");
                string cmd;
                if (!readTokenFromContestant(cmd)) finish(_pe, "Unexpected EOF waiting for command");

                if (cmd == "Q") {
                    long long kll = readLLOrPE("k");
                    if (kll < 1 || kll > n / 2) {
                        printToContestantLine("-1");
                        finish(_pe, "Invalid k in query");
                    }
                    int k = (int)kll;

                    vector<int> xs(k), ys(k);
                    vector<int> used(n + 1, 0);

                    for (int i = 0; i < k; i++) {
                        long long xll = readLLOrPE("x_i");
                        long long yll = readLLOrPE("y_i");
                        if (xll < 1 || xll > n || yll < 1 || yll > n || xll == yll) {
                            printToContestantLine("-1");
                            finish(_pe, "Invalid pair endpoints");
                        }
                        int x = (int)xll, y = (int)yll;
                        if (used[x] || used[y]) {
                            printToContestantLine("-1");
                            finish(_pe, "Coin appears more than once in a batch");
                        }
                        used[x] = used[y] = 1;
                        xs[i] = x;
                        ys[i] = y;
                    }

                    queries++;

                    string ans;
                    ans.reserve(k);
                    for (int i = 0; i < k; i++) {
                        char a = col[xs[i] - 1];
                        char b = col[ys[i] - 1];
                        ans.push_back(a == b ? '1' : '0');
                    }
                    printToContestantLine(ans);
                } else if (cmd == "A") {
                    long long k1ll = readLLOrPE("k1");
                    long long k2ll = readLLOrPE("k2");
                    long long k3ll = readLLOrPE("k3");
                    if (k1ll < 0 || k2ll < 0 || k3ll < 0 || k1ll + k2ll + k3ll != n) {
                        finish(_pe, "Invalid pile sizes");
                    }
                    int k1 = (int)k1ll, k2 = (int)k2ll, k3 = (int)k3ll;

                    array<vector<int>, 3> piles;
                    piles[0].resize(k1);
                    piles[1].resize(k2);
                    piles[2].resize(k3);

                    vector<int> seen(n + 1, 0);

                    auto readCoin = [&](const string& what) -> int {
                        long long vll = readLLOrPE(what);
                        if (vll < 1 || vll > n) finish(_pe, "Coin index out of range");
                        int v = (int)vll;
                        if (seen[v]) finish(_pe, "Coin appears multiple times in answer");
                        seen[v] = 1;
                        return v;
                    };

                    for (int i = 0; i < k1; i++) piles[0][i] = readCoin("pile1 coin");
                    for (int i = 0; i < k2; i++) piles[1][i] = readCoin("pile2 coin");
                    for (int i = 0; i < k3; i++) piles[2][i] = readCoin("pile3 coin");

                    for (int i = 1; i <= n; i++) {
                        if (!seen[i]) finish(_pe, "Some coin missing from answer");
                    }

                    array<char, 3> pileColor;
                    pileColor.fill(0);

                    for (int p = 0; p < 3; p++) {
                        if (piles[p].empty()) continue;
                        char pc = col[piles[p][0] - 1];
                        for (int v : piles[p]) {
                            if (col[v - 1] != pc) finish(_wa, "Pile contains mixed colors");
                        }
                        pileColor[p] = pc;
                    }

                    array<int, 256> colorToPile;
                    colorToPile.fill(-1);
                    for (int p = 0; p < 3; p++) {
                        char pc = pileColor[p];
                        if (pc == 0) continue;
                        unsigned char uc = (unsigned char)pc;
                        if (colorToPile[uc] != -1 && colorToPile[uc] != p) finish(_wa, "Same color split across piles");
                        colorToPile[uc] = p;
                    }

                    answered = true;
                } else {
                    finish(_pe, "Unknown command token");
                }
            }
        }

        
        
        string extra;
        if (readTokenFromContestant(extra)) finish(_pe, "Extra output after completing all test cases");

        finish(_ok, "OK");
    } catch (const std::exception& e) {
        finish(_pe, string("Exception: ") + e.what());
    } catch (...) {
        finish(_pe, "Unknown exception");
    }
    return 0;
}


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

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

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

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

static bool isIntegerToken(const string& s) {
    if (s.empty()) return false;
    int i = 0;
    if (s[0] == '-') {
        if ((int)s.size() == 1) return false;
        i = 1;
    }
    for (; i < (int)s.size(); ++i) if (!isdigit((unsigned char)s[i])) return false;
    return true;
}

static bool parseLongLong(const string& s, long long& out) {
    if (!isIntegerToken(s)) return false;
    try {
        size_t idx = 0;
        long long v = stoll(s, &idx, 10);
        if (idx != s.size()) return false;
        out = v;
        return true;
    } catch (...) {
        return false;
    }
}

static bool readTokenFromContestant(string& tok) {
    tok.clear();
    if (!(cin >> tok)) return false;
    return true;
}

static bool readLongLongFromContestant(long long& x) {
    string s;
    if (!readTokenFromContestant(s)) return false;
    return parseLongLong(s, x);
}

static vector<int> genColorsDeterministic(int n, int caseIdx0) {
    vector<int> c(n + 1, 0);
    if (n == 1) {
        c[1] = 0;
        return c;
    }
    if (n == 2) {
        c[1] = 0;
        c[2] = (caseIdx0 & 1) ? 0 : 1;
        return c;
    }
    c[1] = 0;
    c[2] = 1;
    c[3] = 2;
    long long add = 7LL * (caseIdx0 + 1);
    for (int i = 4; i <= n; ++i) c[i] = (int)((i + add) % 3);
    return c;
}

static vector<int> parseColorsString(const string& s, int n) {
    if ((int)s.size() != n) finish(_pe, "invalid hidden input: colors length mismatch");
    vector<int> c(n + 1, 0);
    for (int i = 1; i <= n; ++i) {
        char ch = s[i - 1];
        if (ch == 'R') c[i] = 0;
        else if (ch == 'G') c[i] = 1;
        else if (ch == 'B') c[i] = 2;
        else finish(_pe, "invalid hidden input: colors contain non-RGB");
    }
    return c;
}

static bool checkAnswerAgainstColors(
    int n,
    const vector<int>& col,
    const array<vector<int>, 3>& piles,
    string& err
) {
    vector<int> seen(n + 1, 0);
    for (int p = 0; p < 3; ++p) {
        for (int x : piles[p]) {
            if (x < 1 || x > n) {
                err = "answer coin out of range";
                return false;
            }
            if (seen[x]) {
                err = "answer coin repeated";
                return false;
            }
            seen[x] = 1;
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (!seen[i]) {
            err = "answer missing coin";
            return false;
        }
    }

    array<int, 3> pileColor;
    pileColor.fill(-1);

    for (int p = 0; p < 3; ++p) {
        int pc = -1;
        for (int x : piles[p]) {
            int cx = col[x];
            if (pc == -1) pc = cx;
            else if (pc != cx) {
                err = "pile contains multiple colors";
                return false;
            }
        }
        pileColor[p] = pc;
    }

    for (int i = 0; i < 3; ++i) {
        if (pileColor[i] == -1) continue;
        for (int j = i + 1; j < 3; ++j) {
            if (pileColor[j] == -1) continue;
            if (pileColor[i] == pileColor[j]) {
                err = "same color split across piles";
                return false;
            }
        }
    }

    err.clear();
    return true;
}

struct HiddenCase {
    int n = 0;
    bool hasColors = false;
    string colors;
};

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

    int t = inf.readInt();
    if (t < 1 || t > 5) finish(_pe, "invalid hidden input: t out of range");

    vector<string> toks;
    while (!inf.seekEof()) toks.push_back(inf.readToken());

    vector<HiddenCase> cases;
    cases.reserve(t);

    int idx = 0;
    for (int ci = 0; ci < t; ++ci) {
        if (idx >= (int)toks.size()) finish(_pe, "invalid hidden input: missing n");
        long long nll = 0;
        if (!parseLongLong(toks[idx], nll)) finish(_pe, "invalid hidden input: n token not integer");
        idx++;
        if (nll < 1 || nll > 100000) finish(_pe, "invalid hidden input: n out of range");
        int n = (int)nll;

        HiddenCase hc;
        hc.n = n;

        if (idx < (int)toks.size()) {
            const string& nxt = toks[idx];
            bool looksLikeColors = ((int)nxt.size() == n);
            if (looksLikeColors) {
                for (char ch : nxt) {
                    if (ch != 'R' && ch != 'G' && ch != 'B') {
                        looksLikeColors = false;
                        break;
                    }
                }
            }
            if (looksLikeColors) {
                hc.hasColors = true;
                hc.colors = nxt;
                idx++;
            }
        }

        cases.push_back(std::move(hc));
    }

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

    cout << t << endl;

    for (int ci = 0; ci < t; ++ci) {
        int n = cases[ci].n;
        vector<int> col = cases[ci].hasColors ? parseColorsString(cases[ci].colors, n)
                                              : genColorsDeterministic(n, ci);

        cout << n << endl;

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

            if (cmd == "Q") {
                long long kll;
                if (!readLongLongFromContestant(kll)) {
                    cout << -1 << endl;
                    finish(_pe, "malformed query: missing k");
                }
                if (kll < 1 || kll > n / 2) {
                    cout << -1 << endl;
                    finish(_pe, "invalid query: k out of range");
                }
                int k = (int)kll;

                vector<int> xs(k), ys(k);
                vector<int> used(n + 1, 0);
                for (int i = 0; i < k; ++i) {
                    long long xll, yll;
                    if (!readLongLongFromContestant(xll) || !readLongLongFromContestant(yll)) {
                        cout << -1 << endl;
                        finish(_pe, "malformed query: missing pair endpoints");
                    }
                    if (xll < 1 || xll > n || yll < 1 || yll > n || xll == yll) {
                        cout << -1 << endl;
                        finish(_pe, "invalid query: endpoints out of range or equal");
                    }
                    int x = (int)xll, y = (int)yll;
                    if (used[x] || used[y]) {
                        cout << -1 << endl;
                        finish(_pe, "invalid query: coin appears multiple times in batch");
                    }
                    used[x] = used[y] = 1;
                    xs[i] = x;
                    ys[i] = y;
                }

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

                string resp;
                resp.reserve(k);
                for (int i = 0; i < k; ++i) {
                    resp.push_back(col[xs[i]] == col[ys[i]] ? '1' : '0');
                }
                cout << resp << endl;
            } else if (cmd == "A") {
                long long k1ll, k2ll, k3ll;
                if (!readLongLongFromContestant(k1ll) || !readLongLongFromContestant(k2ll) || !readLongLongFromContestant(k3ll)) {
                    finish(_pe, "malformed answer header");
                }
                if (k1ll < 0 || k2ll < 0 || k3ll < 0) finish(_pe, "negative pile size");
                if (k1ll + k2ll + k3ll != n) finish(_pe, "pile sizes do not sum to n");
                int k1 = (int)k1ll, k2 = (int)k2ll, k3 = (int)k3ll;

                array<vector<int>, 3> piles;
                piles[0].resize(k1);
                piles[1].resize(k2);
                piles[2].resize(k3);

                for (int i = 0; i < k1; ++i) {
                    long long v;
                    if (!readLongLongFromContestant(v)) finish(_pe, "malformed answer: missing coin in pile 1");
                    piles[0][i] = (int)v;
                }
                for (int i = 0; i < k2; ++i) {
                    long long v;
                    if (!readLongLongFromContestant(v)) finish(_pe, "malformed answer: missing coin in pile 2");
                    piles[1][i] = (int)v;
                }
                for (int i = 0; i < k3; ++i) {
                    long long v;
                    if (!readLongLongFromContestant(v)) finish(_pe, "malformed answer: missing coin in pile 3");
                    piles[2][i] = (int)v;
                }

                string err;
                if (!checkAnswerAgainstColors(n, col, piles, err)) {
                    finish(_wa, err);
                }
                break; 
            } else {
                finish(_pe, "unknown command (expected Q or A)");
            }
        }
    }

    finish(_ok, "ok");
}


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

static int igcd(int a, int b) {
    while (b) {
        int t = a % b;
        a = b;
        b = t;
    }
    return a;
}

static string genBalancedShuffle(int n) {
    int c0 = n / 3;
    int c1 = n / 3;
    int c2 = n - c0 - c1;
    vector<char> v;
    v.reserve(n);
    v.insert(v.end(), c0, 'R');
    v.insert(v.end(), c1, 'G');
    v.insert(v.end(), c2, 'B');
    for (int i = n - 1; i >= 1; --i) {
        int j = rnd.next(0, i);
        swap(v[i], v[j]);
    }
    return string(v.begin(), v.end());
}

static string genMinorityScatter(int n) {
    if (n == 1) return "R";
    if (n == 2) return "RG";

    vector<char> s(n, '?');

    int maxM = min(1200, n - 2);
    int m = rnd.next(1, maxM);

    int step = rnd.next(1, n - 1);
    while (igcd(step, n) != 1) step = rnd.next(1, n - 1);
    int offset = rnd.next(0, n - 1);

    for (int i = 0; i < m; ++i) {
        int pos = (offset + (long long)i * step) % n;
        s[pos] = 'B';
    }

    int rem = n - m;
    int targetR = rem / 2;
    int targetG = rem - targetR;
    int usedR = 0, usedG = 0;

    for (int i = 0; i < n; ++i) {
        if (s[i] != '?') continue;
        bool preferR = (i & 1) == 0;
        char put;
        if ((preferR && usedR < targetR) || usedG == targetG) put = 'R';
        else put = 'G';
        s[i] = put;
        usedR += (put == 'R');
        usedG += (put == 'G');
    }

    if (count(s.begin(), s.end(), 'R') == 0) s[0] = 'R';
    if (count(s.begin(), s.end(), 'G') == 0) s[n / 2] = 'G';
    if (count(s.begin(), s.end(), 'B') == 0) s[n - 1] = 'B';

    return string(s.begin(), s.end());
}

static string genRuns(int n) {
    if (n == 1) return "R";
    if (n == 2) return "RG";

    vector<char> cols = {'R', 'G', 'B'};
    string s;
    s.reserve(n);

    int last = -1;
    while ((int)s.size() < n) {
        int c = rnd.next(0, 2);
        if (c == last) c = (c + 1 + rnd.next(0, 1)) % 3;
        int remaining = n - (int)s.size();
        int lenMax = min(remaining, 300);
        int len = rnd.next(1, lenMax);
        s.append(len, cols[c]);
        last = c;
    }

    bool hasR = s.find('R') != string::npos;
    bool hasG = s.find('G') != string::npos;
    bool hasB = s.find('B') != string::npos;
    if (!hasR) s[0] = 'R';
    if (!hasG) s[n / 2] = 'G';
    if (!hasB) s[n - 1] = 'B';

    return s;
}

static string buildColors(int n, long long seedVal) {
    if (n == 1) return "R";
    if (n == 2) {
        if ((seedVal & 1LL) == 0) return "RG";
        return "RR";
    }
    if (seedVal == 1) return string(n, 'R');
    if (seedVal == 2) return genBalancedShuffle(n);
    if (seedVal == 3) return genMinorityScatter(n);

    int kind = rnd.next(0, 2);
    if (kind == 0) return genBalancedShuffle(n);
    if (kind == 1) return genMinorityScatter(n);
    return genRuns(n);
}

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

    string mode = opt<string>("mode", "non");
    int nOpt = opt<int>("n", 100000);
    nOpt = max(1, min(100000, nOpt));

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

    int n;
    if (seedVal == 1) n = 1;                 
    else if (seedVal == 2) n = 100000;       
    else if (seedVal == 3) n = 99991;        
    else n = nOpt;

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

    if (mode == "non") {
        string colors = buildColors(n, seedVal);
        cout << colors << "\n";
    } else if (mode == "adp") {
        
    } else {
        
        string colors = buildColors(n, seedVal);
        cout << colors << "\n";
    }

    return 0;
}