Problem: cf2150_e1
Difficulty: medium
Categories: search, math
Time limit: 5000 ms, memory limit: 256 MB

AdhesiveWombat - Overdrive

⠀

The two versions have different constraints on $t$, $n$, and the maximum number of queries, and solving one of the two versions does not necessarily solve the other. You may want to read both versions.

This is an interactive problem.

There is a hidden array $a_1, a_2, \ldots, a_{2n-1}$ containing all the numbers from $1$ to $n$, and all of them appear twice except one (which only appears once).

You can ask queries in the following format, where $S$ is a subset of $\{1, 2, \ldots, 2n-1\}$ and $x$ is an integer in $[1, n]$:

* $\texttt{ask(S, x)}$: does there exist $i \in S$ such that $a_i = x$?

Find the number appearing exactly once, using at most $4n + 2 \lceil \log_2 n \rceil$ queries. You don't need to find its position.

Note that the interactor is not adaptive, which means that the hidden array does not depend on the queries you make.

Input

Each test contains multiple test cases. The first line contains the number of test cases $t$ ($1 \le t \le 4000$). The description of the test cases follows.

The first line of each test case contains a single integer $n$ ($1 \le n \le 300$) — the maximum value in the hidden array $a_1, a_2, \ldots, a_{2n-1}$.

It is guaranteed that the sum of $n^2$ over all test cases does not exceed $4 \cdot 10^5$.

There are exactly $80$ tests in this problem (including the example).

Interaction

For each test case, first read a single integer $n$. If the integer you read is $-1$, it means that the answer to the previous test case was wrong, and you should exit immediately.

You may ask up to $4n + 2 \lceil \log_2 n \rceil$ queries in each test case.

To ask a query, print a line in the format $\texttt{? x |S| S_1 S_2... S_|S|}$ with $1 \leq x \leq n$, $1 \leq S_1, S_2, \ldots, S_{|S|} \leq 2n-1$, and all the $S_i$ distinct.

As a response to the query, you will get $1$ if the answer is yes, $0$ if the answer is no, and $-1$ if you made an invalid query. You should exit immediately if you receive a $-1$.

To output an answer, you should print $\texttt{! y}$, where $y$ is the number that appears exactly once. Printing the answer doesn't count as a query.

See the interaction example for more clarity.

If you ask too many queries, you ask a malformed query, or your answer is wrong, you will get $\texttt{Wrong answer}$.

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

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

Note that the interactor is not adaptive, which means that the hidden arrays do not depend on the queries you make.

Example

Input

```
2
2

0

3

1

1

1

1
```

Output

```? 1 2 1 2! 1? 1 2 1 4? 2 2 1 4? 2 1 2? 1 1 5! 3
```

Note

In the first test case, $n = 2$, so the hidden array has length $2n-1 = 3$. One possible hidden array consistent with the interaction is $[2, 2, 1]$, where $1$ appears once and $2$ appears twice.

|  |  |  |  |
| --- | --- | --- | --- |
| # | Contestant prints | Interactor replies | Explanation |
| 1 |? 1 2 1 2 | 0 | Query: does $a_1=1$ or $a_2=1$? No (they are both $2$). Therefore $1$ can appear at most once (only in position $3$), so the number appearing exactly once must be $1$. |
| 2 |! 1 |  | Output the answer. |

We have asked $1$ query (printing the answer does not count as a query), which is less than the maximum allowed number of queries ($4n + 2 \lceil \log_2 n \rceil = 10$).

$\color{white}{2}$

In the second testcase, $n = 3$, so the hidden array has length $5$. One possible hidden array consistent with the interaction is $[1, 2, 3, 2, 1]$, where $3$ appears once, and $1$ and $2$ appear twice.

|  |  |  |  |
| --- | --- | --- | --- |
| # | Contestant prints | Interactor replies | Explanation |
| 1 |? 1 2 1 4 | 1 | Check if $a_1$ or $a_4$ equals $1$. Yes ($a_1=1$). |
| 2 |? 2 2 1 4 | 1 | Check if $a_1$ or $a_4$ equals $2$. Yes ($a_4=2$). |
| 3 |? 2 1 2 | 1 | Check if $a_2=2$. Yes. |
| 4 |? 1 1 5 | 1 | Check if $a_5=1$. Yes. |
| 5 |! 3 |  | We know that $3$ cannot appear neither in positions $1$ and $4$ (which contain $1$ and $2$ in some order), nor in positions $2$ and $5$ (which contain $2$ and $1$, respectively). So the answer must be $3$. |

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

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

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

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

struct TestCase {
    int n = 0;
    vector<int> a; 
    int single = -1;
};

static int ceil_log2_int(int n) {
    int k = 0;
    int p = 1;
    while (p < n) {
        p <<= 1;
        ++k;
    }
    return k;
}

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

    int t = 0;
    vector<TestCase> tests;
    try {
        t = inf.readInt(1, 4000, "t");
        tests.resize(t);

        long long total_limit = 0;
        for (int tc = 0; tc < t; ++tc) {
            int n = inf.readInt(1, 300, "n");
            int m = 2 * n - 1;

            vector<int> a(m + 1, 0);
            vector<int> freq(n + 1, 0);
            for (int i = 1; i <= m; ++i) {
                int v = inf.readInt(1, n, "a_i");
                a[i] = v;
                freq[v]++;
            }

            int single = -1;
            for (int v = 1; v <= n; ++v) {
                if (freq[v] == 1) {
                    if (single != -1) {
                        
                        query_limit = total_limit;
                        log_metrics();
                        quitf(_fail, "Invalid hidden input: multiple singletons");
                    }
                    single = v;
                } else if (freq[v] == 0 || freq[v] == 2) {
                    
                } else {
                    query_limit = total_limit;
                    log_metrics();
                    quitf(_fail, "Invalid hidden input: value %d has freq %d", v, freq[v]);
                }
            }
            if (single == -1) {
                query_limit = total_limit;
                log_metrics();
                quitf(_fail, "Invalid hidden input: no singleton");
            }

            tests[tc].n = n;
            tests[tc].a = std::move(a);
            tests[tc].single = single;

            long long lim = 4LL * n + 2LL * ceil_log2_int(n);
            total_limit += lim;
        }

        query_limit = total_limit;
    } catch (...) {
        
        log_metrics();
        throw;
    }

    
    log_metrics();

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

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

    for (int tc = 0; tc < t; ++tc) {
        const int n = tests[tc].n;
        const int m = 2 * n - 1;
        const vector<int>& a = tests[tc].a;
        const int correct = tests[tc].single;

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

        bool answered = false;
        while (!answered) {
            string tok;
            if (!(cin >> tok)) finish(_pe, "Unexpected EOF from participant");

            if (tok == "?") {
                long long x_ll = 0, k_ll = 0;
                if (!(cin >> x_ll >> k_ll)) {
                    cout << -1 << "\n";
                    cout.flush();
                    finish(_pe, "Malformed query header");
                }
                if (x_ll < 1 || x_ll > n || k_ll < 1 || k_ll > m) {
                    cout << -1 << "\n";
                    cout.flush();
                    finish(_pe, "Invalid query parameters");
                }
                int x = (int)x_ll;
                int k = (int)k_ll;

                vector<char> seen(m + 1, 0);
                bool ok = true;
                bool exists = false;
                for (int i = 0; i < k; ++i) {
                    long long s_ll = 0;
                    if (!(cin >> s_ll)) {
                        cout << -1 << "\n";
                        cout.flush();
                        finish(_pe, "Malformed query set");
                    }
                    if (s_ll < 1 || s_ll > m) ok = false;
                    else {
                        int s = (int)s_ll;
                        if (seen[s]) ok = false;
                        seen[s] = 1;
                        if (a[s] == x) exists = true;
                    }
                }

                if (!ok) {
                    cout << -1 << "\n";
                    cout.flush();
                    finish(_pe, "Invalid query indices");
                }

                if (queries + 1 > hard_cap) {
                    cout << -1 << "\n";
                    cout.flush();
                    finish(_pe, "Hard cap exceeded");
                }
                ++queries;

                cout << (exists ? 1 : 0) << "\n";
                cout.flush();
            } else if (tok == "!") {
                long long y_ll = 0;
                if (!(cin >> y_ll)) finish(_pe, "Malformed answer");
                if (y_ll < 1 || y_ll > n) finish(_wa, "Answer out of range");
                int y = (int)y_ll;
                if (y != correct) finish(_wa, "Wrong answer");
                answered = true;
            } else {
                finish(_pe, "Unexpected token");
            }
        }
    }

    finish(_ok, "OK");
    return 0;
}


Adaptive interactor (C++):

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

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 bool isPow2(int x) {
    return x > 0 && (x & (x - 1)) == 0;
}

static vector<int> makeSymmetric(int n, int singleVal) {
    int m = 2 * n - 1;
    vector<int> a(m + 1, 0);
    vector<int> rest;
    rest.reserve(n - 1);
    for (int v = 1; v <= n; ++v) if (v != singleVal) rest.push_back(v);
    shuffleVec(rest);

    for (int i = 1; i <= n - 1; ++i) a[i] = rest[i - 1];
    a[n] = singleVal;
    for (int i = 1; i <= n - 1; ++i) a[n + i] = rest[n - 1 - i];
    return a;
}

static vector<int> makeORCollision(int n, int singleVal) {
    int m = 2 * n - 1; 
    vector<int> a(m + 1, 0);
    a[m] = singleVal; 

    vector<int> vals;
    vals.reserve(n - 1);
    for (int v = 1; v <= n; ++v) if (v != singleVal) vals.push_back(v);
    shuffleVec(vals);

    vector<pair<int,int>> pairs;
    pairs.reserve(n - 1);
    for (int p = 1; p <= m - 1; ++p) {
        int q = (m ^ p);
        if (p < q) pairs.push_back({p, q});
    }
    
    shuffleVec(pairs);

    int need = n - 1;
    if ((int)pairs.size() != need) {
        
        return makeSymmetric(n, singleVal);
    }
    for (int i = 0; i < need; ++i) {
        int p = pairs[i].first;
        int q = pairs[i].second;
        a[p] = vals[i];
        a[q] = vals[i];
    }
    return a;
}

static vector<int> makeRandomShuffle(int n, int singleVal) {
    int m = 2 * n - 1;
    vector<int> bag;
    bag.reserve(m);
    for (int v = 1; v <= n; ++v) {
        bag.push_back(v);
        if (v != singleVal) bag.push_back(v);
    }
    shuffleVec(bag);
    vector<int> a(m + 1, 0);
    for (int i = 1; i <= m; ++i) a[i] = bag[i - 1];
    return a;
}

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

    string mode = opt<string>("mode", "non");
    int nArg = opt<int>("n", -1);
    int yArg = opt<int>("y", -1);
    int maxN = opt<int>("maxn", 300);
    int minN = opt<int>("minn", 250);

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

    auto pickN = [&]() -> int {
        if (nArg != -1) return nArg;
        if (seedVal == 1) return 1;
        if (seedVal == 2) return 300;
        if (seedVal == 3) return 256;

        int roll = rnd.next(0, 99);
        if (roll < 60) return 256;
        int lo = minN, hi = maxN;
        if (lo < 1) lo = 1;
        if (hi > 300) hi = 300;
        if (lo > hi) swap(lo, hi);
        if (lo == hi) return lo;
        return rnd.next(lo, hi);
    };

    auto pickY = [&](int n) -> int {
        if (yArg != -1) return yArg;
        if (seedVal == 1) return 1;
        if (seedVal == 2) return n; 
        if (seedVal == 3) return 1;
        return rnd.next(1, n);
    };

    int n = pickN();
    ensuref(1 <= n && n <= 300, "n out of bounds: %d", n);
    int y = pickY(n);
    ensuref(1 <= y && y <= n, "y out of bounds: %d (n=%d)", y, n);

    cout << 1 << "\n";
    if (mode == "non") {
        cout << n << "\n";
        vector<int> a;

        if (seedVal == 1) {
            a.assign(2 * n, 0);
            a[1] = 1;
        } else if (seedVal == 2) {
            
            a.assign(2 * n, 0);
            for (int i = 1; i <= n - 1; ++i) a[i] = i;
            a[n] = n;
            for (int i = 1; i <= n - 1; ++i) a[n + i] = (n - i);
        } else if (seedVal == 3) {
            if (isPow2(n) && n >= 2) a = makeORCollision(n, y);
            else a = makeSymmetric(n, y);
        } else {
            int roll = rnd.next(0, 99);
            if (isPow2(n) && n >= 2 && roll < 70) {
                a = makeORCollision(n, y);
            } else if (roll < 90) {
                a = makeSymmetric(n, y);
            } else {
                a = makeRandomShuffle(n, y);
            }
        }

        int m = 2 * n - 1;
        for (int i = 1; i <= m; ++i) {
            if (i > 1) cout << ' ';
            cout << a[i];
        }
        cout << "\n";
    } else if (mode == "adp") {
        
        cout << n << " " << y << "\n";
    } else {
        quitf(_fail, "Unknown --mode: %s", mode.c_str());
    }

    return 0;
}