Problem: cf2183_g
Difficulty: medium
Categories: math
Time limit: 3000 ms, memory limit: 256 MB

This is an interactive problem.

There are $n$ snakes on the number line. The $i$\-th snake is located at the position $a_i$ and has a speed $s_i$. You know the position of each snake, and that the speed of each snake is an integer from $0$ to $2$ inclusive, but you do not know the exact speed of each snake. It is guaranteed that no two snakes are at the same position.

To figure out the snakes' speed, you may give **up to $3$** instructions. Each instruction should be given in the form of a binary string of length $m$ containing letters L and R ($1 \leq m \leq 4n$). After receiving this instruction, the snakes will move for $m$ seconds. On the $i$\-th second, if $s_i=$L, then all snakes move left for that second. Otherwise, all snakes move right for that second. If two snakes are at the same location at any given point (including if the time is not an integer number of seconds), the faster snake is removed from the board. After all $m$ seconds have passed, you are given the number of remaining snakes, as well as the location of all remaining snakes. Note that each instruction is independent of each other – that means that all snakes are revived and moved to their original positions.

Your task is to find the speed of all snakes. However, it may be the case that it is impossible to find the speed of at least one snake. If this is the case, you must report \-1 instead. You should only output \-1 if it is impossible to figure out the speed of at least one snake, no matter which instructions are given. **If you report \-1 when there are a series of at most $3$ instructions that will uniquely determine the speed of each snake, you will get the Wrong Answer verdict.** Similarly, you will receive the Wrong Answer verdict if you did not report \-1 when the configuration is impossible to determine, even if you correctly guessed the speeds.

Input

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

The first line of each test case contains an integer $n$ – the number of snakes ($2 \leq n \leq 10^5$).

The second line contains $n$ integers $a_1,a_2,\ldots,a_n$ ($1 \leq a_1<a_2<\ldots<a_n \leq 4n$) – the initial position of all snakes.

It is guaranteed that the sum of $n$ across all test cases does not exceed $10^5$.

Interaction

After reading in the position of all snakes, interaction begins. To give an instruction, output a line in the following format:

-   ? s

You should guarantee that $s$ contains only letters L and R, and has length between $1$ and $4n$ inclusive.

The jury will return a line in the following format:

-   $k\:b_1\:b_2\:\ldots\:b_k\:(1 \leq k \leq n, -10^9 \leq b_1<b_2<\ldots<b_k \leq 10^9$)

Here, $k$ is the number of snakes that remain after the full instruction, and $b_1,b_2,\ldots,b_k$ are their final positions.

When you are ready to output the answer, output a line in the following format:

-   If it is impossible to determine the speed of all snakes, output ! -1
-   Otherwise, output ! $s_1$ $s_2$ $\ldots$ $s_n$ ($0 \leq s_i \leq 2$). Here, $s_i$ should denote the speed of the $i$\-th snake as given in the input.

Printing the answer does not count as giving an instruction.

After this, proceed to the next case or terminate the program if this is the last test case.

The interactor is **not** adaptive. This means that the speed of all snakes is fixed in advance and does not change in the interaction process. It is further guaranteed that there exists a solution – that is, the resulting positions of all snakes after movements are consistent with their speeds.

After printing each query do not forget to output the end of line and flush$^{\text{∗}}$ the output. Otherwise, you will get Idleness limit exceeded verdict.

If, at any interaction step, you read $-1$ instead of valid data, your solution must exit immediately. This means that your solution will receive Wrong answer because of an invalid query or any other mistake. Failing to exit can result in an arbitrary verdict because your solution will continue to read from a closed stream.


$^{\text{∗}}$To flush, use:

-   fflush(stdout) or cout.flush() in C++;
-   sys.stdout.flush() in Python;
-   see the documentation for other languages.

Example

Input

```
7
2
1 2

1 1

2
1 6

2 1 4

3
2 3 4

2 2 4

3
2 3 4

3 5 6 7

5
1 3 8 14 15

5
1 2 3 4 5

4
5 6 7 8
```

Output

```



? L

! 0 1


? LRLL

! 0 1


? RRR

! -1


? RRR

! 1 1 1


! 2 1 0 0 1


! 0 2 2 2 0


! 0 1 2 0

```
Note
**Note**

In the first test case, the speed of the snakes is $0$ and $1$. The program begins by giving the instruction L. The right snake moves from $2$ to $1$ while the left snake does not move. However, since now both snakes occupy the position $1$, the one with the higher speed (the right snake) is removed. Therefore, there is only one snake remaining, and it is at position $1$. At this point, the program decides to guess the speed of snakes as $0$ and $1$, which is correct, so this test case is passed. Note that although the speeds $[0,2]$ would also result in there being $1$ snake at position $1$ at the end, we cannot report $-1$, as we can show there is a series of instructions that will differentiate $[0,2]$ and $[0,1]$.

In the third test case, we conclude that the speed of both the first snake and the third snake is $0$, and we can show there is no way to differentiate the speed of the middle snake between $1$ and $2$. Therefore, reporting \-1 is correct in this case.

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

struct Event {
    long long time2;
    int left;
    int right;
    int remove;
};

struct EventCmp {
    bool operator()(const Event& a, const Event& b) const {
        if (a.time2 != b.time2) return a.time2 > b.time2; 
        if (a.left != b.left) return a.left > b.left;
        return a.right > b.right;
    }
};

static void push_event_if_needed(
    priority_queue<Event, vector<Event>, EventCmp>& pq,
    const vector<long long>& pos2,
    const vector<int>& speed,
    int dir,
    long long duration2,
    long long current_time2,
    int left,
    int right
) {
    if (left < 0 || right < 0) return;

    int remove = -1;
    int diff = 0;
    if (dir == 1) {
        if (speed[left] <= speed[right]) return;
        remove = left;
        diff = speed[left] - speed[right];
    } else {
        if (speed[right] <= speed[left]) return;
        remove = right;
        diff = speed[right] - speed[left];
    }
    if (diff <= 0) return;

    long long dist2 =
        (pos2[right] - pos2[left]) + 1LL * dir * (speed[right] - speed[left]) * current_time2;
    if (dist2 < 0) return;

    long long dt2 = dist2 / diff;
    long long t2 = current_time2 + dt2;
    if (t2 > duration2) return;

    pq.push(Event{t2, left, right, remove});
}

static vector<long long> simulate_query(const vector<long long>& a, const vector<int>& speed, const string& ops) {
    int n = (int)a.size();
    vector<long long> pos2(n);
    vector<int> prv(n, -1), nxt(n, -1);
    vector<char> alive(n, 1);
    for (int i = 0; i < n; ++i) {
        pos2[i] = 2LL * a[i];
        prv[i] = i - 1;
        nxt[i] = (i + 1 < n) ? (i + 1) : -1;
    }
    int head = (n > 0) ? 0 : -1;

    
    vector<pair<char, int>> segs;
    for (char c : ops) {
        if (segs.empty() || segs.back().first != c) segs.push_back({c, 1});
        else segs.back().second++;
    }

    for (const auto& seg : segs) {
        char c = seg.first;
        int len = seg.second;
        int dir = (c == 'R') ? 1 : -1;
        long long duration2 = 2LL * len;

        priority_queue<Event, vector<Event>, EventCmp> pq;
        for (int i = head; i != -1 && nxt[i] != -1; i = nxt[i]) {
            int j = nxt[i];
            push_event_if_needed(pq, pos2, speed, dir, duration2, 0, i, j);
        }

        while (!pq.empty()) {
            Event ev = pq.top();
            pq.pop();
            if (ev.time2 > duration2) break;

            int i = ev.left;
            int j = ev.right;
            if (i < 0 || j < 0) continue;
            if (!alive[i] || !alive[j]) continue;
            if (nxt[i] != j || prv[j] != i) continue;

            int rem = ev.remove;
            if (rem != i && rem != j) {
                finish(_pe, "Internal error: bad remove index");
            }

            alive[rem] = 0;

            long long t2 = ev.time2;
            if (rem == i) {
                int p = prv[i];
                prv[j] = p;
                if (p != -1) nxt[p] = j;
                else head = j;

                prv[i] = nxt[i] = -1;

                if (p != -1) push_event_if_needed(pq, pos2, speed, dir, duration2, t2, p, j);
            } else {
                int q = nxt[j];
                nxt[i] = q;
                if (q != -1) prv[q] = i;

                prv[j] = nxt[j] = -1;

                if (q != -1) push_event_if_needed(pq, pos2, speed, dir, duration2, t2, i, q);
            }
        }

        
        for (int i = head; i != -1; i = nxt[i]) {
            pos2[i] += 1LL * dir * speed[i] * duration2;
        }
    }

    vector<long long> out;
    for (int i = head; i != -1; i = nxt[i]) {
        if ((pos2[i] & 1LL) != 0) {
            finish(_pe, "Internal error: non-integer position at segment boundary");
        }
        out.push_back(pos2[i] / 2);
    }
    return out;
}

struct ExpectedAnswer {
    bool impossible;
    vector<int> speeds;
};

static ExpectedAnswer compute_expected(const vector<long long>& a, const vector<int>& speed) {
    const int n = (int)a.size();

    vector<long long> L = simulate_query(a, speed, "L");
    vector<long long> LR = simulate_query(a, speed, "LR");
    vector<long long> R = simulate_query(a, speed, "R");

    if (L.size() != LR.size()) {
        finish(_pe, "Internal error: |L| != |LR|");
    }

    vector<int> v(n, -1);
    int ptr = 0;
    for (int i = 0; i < (int)LR.size(); ++i) {
        while (ptr < n && a[ptr] != LR[i]) ptr++;
        if (ptr >= n) finish(_pe, "Internal error: LR position not found in a[]");
        v[ptr] = (int)(a[ptr] - L[i]);
    }

    if (v[0] == -1) finish(_pe, "Internal error: v[0] unset");

    for (int i = 1; i < n; ++i) {
        if (v[i] != -1) continue;
        if (v[i - 1] == 1) {
            if (a[i - 1] + 1 != a[i]) finish(_pe, "Internal error: expected consecutive positions");
            v[i] = 2;
            continue;
        }
        if (v[i - 1] != 0) finish(_pe, "Internal error: expected v[i-1] in {0,1}");
        if (a[i - 1] + 2 == a[i]) {
            v[i] = 2;
            continue;
        }
        if (a[i - 1] + 1 != a[i]) finish(_pe, "Internal error: expected gap 1 or 2");
        if (i + 1 < n && v[i + 1] == -1) {
            v[i + 1] = 2;
        }
    }

    for (int i = 1; i + 1 < n; ++i) {
        if (v[i] == -1 && v[i - 1] == 0 && v[i + 1] == 0 && a[i + 1] - a[i - 1] == 2) {
            return ExpectedAnswer{true, {}};
        }
    }

    for (int i = 1; i < n; ++i) {
        if (v[i] != -1) continue;
        auto it = lower_bound(R.begin(), R.end(), a[i - 1]);
        if (it == R.end()) finish(_pe, "Internal error: lower_bound failed in R");
        int pos = (int)(it - R.begin());
        if (pos + 1 >= (int)R.size()) finish(_pe, "Internal error: pos+1 out of range in R");
        v[i] = (int)(R[pos + 1] - a[i]);
    }

    for (int i = 0; i < n; ++i) {
        if (v[i] < 0 || v[i] > 2) finish(_pe, "Internal error: invalid expected speed");
    }

    return ExpectedAnswer{false, v};
}

static bool validate_ops(const string& s, int n) {
    if ((int)s.size() < 1 || (int)s.size() > 4 * n) return false;
    for (char c : s) {
        if (c != 'L' && c != 'R') return false;
    }
    return true;
}

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

    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t = inf.readInt(1, 1000, "t");
    cout << t << endl;
    cout.flush();

    for (int tc = 0; tc < t; ++tc) {
        int n = inf.readInt(2, 100000, "n");
        vector<long long> a(n);
        for (int i = 0; i < n; ++i) a[i] = inf.readInt(1, 4 * n, "a_i");

        vector<int> speed(n);
        for (int i = 0; i < n; ++i) speed[i] = inf.readInt(0, 2, "s_i");

        ExpectedAnswer expected = compute_expected(a, speed);

        cout << n << endl;
        for (int i = 0; i < n; ++i) {
            if (i) cout << " ";
            cout << a[i];
        }
        cout << endl;
        cout.flush();

        int q = 0;
        const int QLIM = 3;
        query_limit += QLIM;
        log_metrics();

        while (true) {
            string tok;
            if (!(cin >> tok)) finish(_wa, "Unexpected EOF from contestant");

            if (tok == "?") {
                string ops;
                if (!(cin >> ops)) finish(_wa, "Bad query format");
                if (q >= QLIM) {
                    cout << -1 << endl;
                    cout.flush();
                    finish(_wa, "Too many queries");
                }
                if (!validate_ops(ops, n)) {
                    cout << -1 << endl;
                    cout.flush();
                    finish(_wa, "Invalid query string");
                }

                vector<long long> resp = simulate_query(a, speed, ops);
                cout << resp.size();
                for (long long x : resp) cout << " " << x;
                cout << endl;
                cout.flush();

                q++;
                queries++;
                if (queries % 200 == 0) log_metrics();
                continue;
            }

            if (!tok.empty() && tok[0] == '?') {
                cout << -1 << endl;
                cout.flush();
                finish(_wa, "Bad query format");
            }

            if (tok == "!") {
                string first_tok;
                if (!(cin >> first_tok)) finish(_wa, "Bad answer format");
                if (first_tok == "-1") {
                    if (!expected.impossible) finish(_wa, "Reported -1 but instance is solvable");
                    break;
                }

                int first_speed = -1;
                try {
                    size_t pos = 0;
                    first_speed = stoi(first_tok, &pos);
                    if (pos != first_tok.size()) finish(_wa, "Bad answer token");
                } catch (...) {
                    finish(_wa, "Bad answer token");
                }

                vector<int> out(n);
                out[0] = first_speed;
                for (int i = 1; i < n; ++i) {
                    if (!(cin >> out[i])) finish(_wa, "Bad answer format");
                }
                for (int i = 0; i < n; ++i) {
                    if (out[i] < 0 || out[i] > 2) finish(_wa, "Speed out of range");
                }
                if (expected.impossible) finish(_wa, "Reported speeds but instance is impossible");
                if (out != expected.speeds) finish(_wa, "Wrong speeds");
                break;
            }

            if (!tok.empty() && tok[0] == '!') finish(_wa, "Bad answer token");
            finish(_wa, "Unexpected token (expected '?' or '!')");
        }
    }

    finish(_ok, "All test cases processed");
    return 0;
}


Adaptive interactor (C++):

Test generator (C++):
#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");
    bool output_speeds = (mode == "non");
    int seed_val = atoi(argv[1]); 

    vector<pair<int, pair<vector<int>, vector<int>>>> cases;
    long long sum_n = 0;
    const long long MAX_SUM_N = 100000;
    const int MAX_T = 1000;

    
    auto add_case = [&](int n, vector<int> a, vector<int> s) {
        cases.push_back({n, {a, s}});
        sum_n += n;
    };

    if (seed_val == 1) {
        
        add_case(2, {1, 2}, {0, 1}); 
        add_case(2, {1, 6}, {0, 0}); 
        add_case(3, {2, 3, 4}, {0, 1, 0}); 
        add_case(5, {1, 2, 3, 4, 5}, {2, 2, 2, 2, 2}); 
        add_case(5, {1, 2, 3, 4, 5}, {0, 0, 0, 0, 0}); 
        add_case(4, {5, 6, 7, 8}, {0, 1, 2, 0}); 
        
        
        {
            int n = 10;
            vector<int> a(n);
            iota(a.begin(), a.end(), 1);
            vector<int> s(n);
            for(int i=0;i<n;++i) s[i] = i%3;
            add_case(n, a, s);
        }
        
        
        while(sum_n + 20 <= MAX_SUM_N && cases.size() < MAX_T) {
             int n = rnd.next(2, 20);
             if (sum_n + n > MAX_SUM_N) break;
             vector<int> a = rnd.distinct(n, 4*n);
             for(int &x : a) x++;
             sort(a.begin(), a.end());
             vector<int> s(n);
             for(int &x : s) x = rnd.next(0, 2);
             add_case(n, a, s);
        }
    } else {
        
        while (sum_n < MAX_SUM_N && cases.size() < MAX_T) {
            long long rem = MAX_SUM_N - sum_n;
            if (rem < 2) break;

            int n_limit = (int)rem;
            int n;
            int type = rnd.next(100);

            
            if (n_limit >= 10000 && type < 5) { 
                n = rnd.next(10000, min(50000, n_limit));
            } else if (n_limit >= 1000 && type < 20) { 
                n = rnd.next(1000, min(10000, n_limit));
            } else if (n_limit >= 100 && type < 50) { 
                n = rnd.next(100, min(1000, n_limit));
            } else { 
                n = rnd.next(2, min(100, n_limit));
            }

            
            vector<int> a;
            int sparsity = rnd.next(3);
            long long max_pos = 4LL * n;
            
            if (sparsity == 0) { 
                
                long long range_cap = n + rnd.next(0, n);
                range_cap = min(range_cap, max_pos);
                a = rnd.distinct(n, (int)range_cap);
            } else if (sparsity == 1) { 
                
                a = rnd.distinct(n, (int)max_pos);
            } else { 
                
                long long range_cap = rnd.next((long long)n, max_pos);
                a = rnd.distinct(n, (int)range_cap);
            }
            
            for(int &x : a) x++; 
            sort(a.begin(), a.end());

            
            vector<int> s(n);
            int pat = rnd.next(5);
            if (pat == 0) fill(s.begin(), s.end(), 0);
            else if (pat == 1) fill(s.begin(), s.end(), 2);
            else if (pat == 2) for(int i=0; i<n; ++i) s[i] = i % 2; 
            else if (pat == 3) for(int i=0; i<n; ++i) s[i] = i % 3; 
            else for(int &x : s) x = rnd.next(0, 2);

            add_case(n, a, s);
        }
    }

    
    cout << cases.size() << "\n";
    for (const auto& c : cases) {
        int n = c.first;
        const auto& a = c.second.first;
        const auto& s = c.second.second;

        cout << n << "\n";
        for (int i = 0; i < n; ++i) {
            cout << a[i] << (i == n - 1 ? "" : " ");
        }
        cout << "\n";

        if (output_speeds) {
            for (int i = 0; i < n; ++i) {
                cout << s[i] << (i == n - 1 ? "" : " ");
            }
            cout << "\n";
        }
    }

    return 0;
}