Problem: cf1762_d
Difficulty: easy
Categories: greedy, math
Time limit: 3000 ms, memory limit: 256 MB

This is an interactive problem.

There is a secret permutation $p$ of $[0,1,2,\ldots,n-1]$. Your task is to find $2$ indices $x$ and $y$ ($1 \leq x, y \leq n$, possibly $x=y$) such that $p_x=0$ or $p_y=0$. In order to find it, you are allowed to ask at most $2n$ queries.

In one query, you give two integers $i$ and $j$ ($1 \leq i, j \leq n$, $i \neq j$) and receive the value of $\gcd(p_i,p_j)^\dagger$.

Note that the permutation $p$ is fixed before any queries are made and does not depend on the queries.

$^\dagger$ $\gcd(x, y)$ denotes the greatest common divisor (GCD) of integers $x$ and $y$. Note that $\gcd(x,0)=\gcd(0,x)=x$ for all positive integers $x$.

Input

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

The first line of each test case contains a single integer $n$ ($2 \leq n \leq 2 \cdot 10^4$).

After reading the integer $n$ for each test case, you should begin the interaction.

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

Interaction

The interaction for each test case begins by reading the integer $n$.

To make a query, output "? $i$ $j$" ($1 \leq i, j \leq n$, $i \neq j$) without quotes. Afterwards, you should read a single integer — the answer to your query $\gcd(p_i,p_j)$. You can make at most $2n$ such queries in each test case.

If you want to print the answer, output "! $x$ $y$" ($1 \leq x, y \leq n$) without quotes. After doing that, read $1$ or $-1$. If $p_x=0$ or $p_y=0$, you'll receive $1$, otherwise you'll receive $-1$. If you receive $-1$, your program must terminate immediately to receive a Wrong Answer verdict. Otherwise, you can get an arbitrary verdict because your solution will continue to read from a closed stream.

If you receive the integer $-1$ instead of an answer or a valid value of $n$, it means your program has made an invalid query, has exceeded the limit of queries, or has given an incorrect answer on the previous test case. Your program must terminate immediately to receive a Wrong Answer verdict. Otherwise, you can get an arbitrary verdict because your solution will continue to read from a closed stream.

After printing a query or the answer, do not forget to output the 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

```
2
2

1

1
5

2

4

1
```

Output

```? 1 2! 1 2? 1 2? 2 3! 3 3
```

Note

In the first test, the interaction proceeds as follows.

|  |  |  |
| --- | --- | --- |
| Solution | Jury | Explanation |
|  | $\texttt{2}$ | There are 2 test cases. |
|  | $\texttt{2}$ | In the first test case, the hidden permutation is $[1,0]$, with length $2$. |
| $\texttt{? 1 2}$ | $\texttt{1}$ | The solution requests $\gcd(p_1,p_2)$, and the jury responds with $1$. |
| $\texttt{! 1 2}$ | $\texttt{1}$ | The solution knows that either $p_1=0$ or $p_2=0$, and prints the answer. Since the output is correct, the jury responds with $1$ and continues to the next test case. |
|  | $\texttt{5}$ | In the second test case, the hidden permutation is $[2,4,0,1,3]$, with length $5$. |
| $\texttt{? 1 2}$ | $\texttt{2}$ | The solution requests $\gcd(p_1,p_2)$, and the jury responds with $2$. |
| $\texttt{? 2 3}$ | $\texttt{4}$ | The solution requests $\gcd(p_2,p_3)$, and the jury responds with $4$. |
| $\texttt{! 3 3}$ | $\texttt{1}$ | The solution has somehow determined that $p_3=0$, and prints the answer. Since the output is correct, the jury responds with $1$. |

Note that the empty lines in the example input and output are for the sake of clarity, and do not occur in the real interaction.

After each test case, make sure to read $1$ or $-1$.

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;


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


long long gcd_val(long long a, long long b) {
    while (b) {
        a %= b;
        swap(a, b);
    }
    return a;
}

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

    
    int t = inf.readInt();
    
    
    cout << t << endl;

    for (int k = 0; k < t; ++k) {
        
        int n = inf.readInt();
        
        
        
        vector<int> p(n);
        for (int i = 0; i < n; ++i) {
            p[i] = inf.readInt();
        }

        
        
        long long limit_this_case = 2LL * n;
        query_limit += limit_this_case;
        
        
        log_metrics();

        
        cout << n << endl;

        int queries_this_case = 0;
        bool case_solved = false;

        
        while (true) {
            string token;
            if (!(cin >> token)) {
                
                finish(_wa, "Unexpected EOF reading token from solution");
            }

            if (token == "!") {
                
                int x, y;
                if (!(cin >> x >> y)) {
                    finish(_wa, "Unexpected EOF reading answer indices");
                }
                
                
                if (x < 1 || x > n || y < 1 || y > n) {
                    cout << -1 << endl;
                    finish(_wa, format("Answer indices %d %d out of range [1, %d]", x, y, n));
                }

                
                
                if (p[x - 1] == 0 || p[y - 1] == 0) {
                    cout << 1 << endl; 
                    case_solved = true;
                    break; 
                } else {
                    cout << -1 << endl; 
                    finish(_wa, format("Incorrect answer: p[%d]=%d, p[%d]=%d, neither is 0", x, p[x-1], y, p[y-1]));
                }

            } else {
                
                int u, v;
                if (token == "?") {
                    if (!(cin >> u >> v)) {
                        finish(_wa, "Unexpected EOF reading query indices");
                    }
                } else {
                    
                    try {
                        u = stoi(token);
                    } catch (...) {
                        cout << -1 << endl;
                        finish(_wa, "Invalid token '" + token + "' (expected '?', '!', or integer)");
                    }
                    if (!(cin >> v)) {
                        finish(_wa, "Unexpected EOF reading second query index");
                    }
                }

                
                queries++;
                queries_this_case++;
                log_metrics(); 

                
                if (queries_this_case > limit_this_case) {
                    cout << -1 << endl;
                    finish(_wa, format("Query limit exceeded for this test case (%d > %lld)", queries_this_case, limit_this_case));
                }

                
                if (u < 1 || u > n || v < 1 || v > n) {
                    cout << -1 << endl;
                    finish(_wa, format("Query indices %d %d out of range [1, %d]", u, v, n));
                }
                if (u == v) {
                    cout << -1 << endl;
                    finish(_wa, format("Query indices must be distinct (%d == %d)", u, v));
                }

                
                long long res = gcd_val(p[u - 1], p[v - 1]);
                cout << res << endl;
            }
        }
        
        if (!case_solved) {
             
             finish(_wa, "Internal logic error: loop exited without solving");
        }
    }

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


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

using namespace std;


static long long total_queries = 0;
static long long global_query_limit = 0;




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


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

struct TestCase {
    int n;
    long long limit;
    vector<int> p; 
};

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

    
    
    
    
    
    
    
    int t = inf.readInt();
    
    
    vector<int> tokens;
    while (!inf.seekEof()) {
        tokens.push_back(inf.readInt());
    }
    
    vector<TestCase> cases;
    size_t cursor = 0;
    
    
    
    mt19937 rng(5489331);

    for (int i = 0; i < t; ++i) {
        if (cursor >= tokens.size()) {
            finish(_fail, "Unexpected end of input (missing n)");
        }
        int n = tokens[cursor++];
        if (n < 2) finish(_fail, "Invalid n < 2 in input");

        TestCase tc;
        tc.n = n;
        tc.limit = 2LL * n; 

        
        
        
        
        
        
        
        
        bool has_p = false;
        if (cursor + n <= tokens.size()) {
            vector<bool> present(n, false);
            bool possible = true;
            for (int k = 0; k < n; ++k) {
                int val = tokens[cursor + k];
                if (val < 0 || val >= n || present[val]) {
                    possible = false;
                    break;
                }
                present[val] = true;
            }
            
            if (possible) {
                
                tc.p.resize(n);
                for (int k = 0; k < n; ++k) {
                    tc.p[k] = tokens[cursor + k];
                }
                cursor += n;
                has_p = true;
            }
        }
        
        if (!has_p) {
            
            tc.p.resize(n);
            iota(tc.p.begin(), tc.p.end(), 0);
            shuffle(tc.p.begin(), tc.p.end(), rng);
        }
        
        cases.push_back(tc);
        global_query_limit += tc.limit;
    }
    
    
    log_metrics();

    
    
    cout << t << endl;

    for (int i = 0; i < t; ++i) {
        const auto& tc = cases[i];
        
        
        cout << tc.n << endl;
        
        int queries_spent = 0;
        bool active = true;
        
        while (active) {
            string kind;
            if (!(cin >> kind)) {
                finish(_wa, "Solution exited prematurely (EOF on stdin)");
            }
            
            if (kind == "?") {
                int u, v;
                if (!(cin >> u >> v)) {
                    finish(_wa, "Invalid query format");
                }
                
                
                if (u < 1 || u > tc.n || v < 1 || v > tc.n || u == v) {
                    cout << -1 << endl; 
                    finish(_wa, "Invalid query parameters (indices out of range or equal)");
                }
                
                queries_spent++;
                total_queries++;
                
                
                if (total_queries % 100 == 0) log_metrics();
                
                if (queries_spent > tc.limit) {
                    cout << -1 << endl;
                    finish(_wa, "Query limit exceeded for this test case");
                }
                
                
                
                int res = std::gcd(tc.p[u-1], tc.p[v-1]);
                cout << res << endl;
                
            } else if (kind == "!") {
                int x, y;
                if (!(cin >> x >> y)) {
                    finish(_wa, "Invalid answer format");
                }
                
                if (x < 1 || x > tc.n || y < 1 || y > tc.n) {
                    cout << -1 << endl;
                    finish(_wa, "Invalid answer parameters");
                }
                
                
                bool correct = (tc.p[x-1] == 0 || tc.p[y-1] == 0);
                if (correct) {
                    cout << 1 << endl; 
                    active = false;
                } else {
                    cout << -1 << endl; 
                    finish(_wa, "Incorrect answer: neither index contains 0");
                }
                
            } else {
                finish(_wa, "Invalid command (expected '?' or '!')");
            }
        }
    }
    
    finish(_ok, "All cases passed");
    return 0;
}


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");
    int sum_n_limit = opt<int>("maxn", 20000);
    int t_arg = opt<int>("t", -1);
    int n_arg = opt<int>("n", -1);

    
    if (sum_n_limit < 2) sum_n_limit = 2;

    
    long long seed_val = -1;
    string seed_str = argv[1];
    try {
        size_t pos;
        seed_val = stoll(seed_str, &pos);
        if (pos != seed_str.size()) seed_val = -1;
    } catch (...) {
        seed_val = -1;
    }

    vector<int> ns;

    
    if (t_arg != -1) {
        if (n_arg != -1) {
            
            if (sum_n_limit < (long long)t_arg * n_arg) {
                
                
                
            }
            for (int i = 0; i < t_arg; ++i) ns.push_back(n_arg);
        } else {
            
            if (sum_n_limit < 2 * t_arg) sum_n_limit = 2 * t_arg;
            ns = rnd.partition(t_arg, sum_n_limit, 2);
        }
    } else if (n_arg != -1) {
        
        if (n_arg < 2) n_arg = 2;
        int t = sum_n_limit / n_arg;
        if (t < 1) t = 1;
        if (t > 10000) t = 10000; 
        for (int i = 0; i < t; ++i) ns.push_back(n_arg);
    } else {
        
        if (seed_val == 1) {
            
            ns.push_back(sum_n_limit);
        } else if (seed_val == 2) {
            
            int t = sum_n_limit / 2;
            if (t > 10000) t = 10000;
            for (int i = 0; i < t; ++i) ns.push_back(2);
        } else if (seed_val == 3) {
            
            int t = 50;
            if (t * 2 > sum_n_limit) t = sum_n_limit / 2;
            ns = rnd.partition(t, sum_n_limit, 2);
        } else {
            
            int type = rnd.next(3);
            int t;
            if (type == 0) t = rnd.next(1, 5);                     
            else if (type == 1) t = rnd.next(10, 100);             
            else t = rnd.next(100, min(2000, sum_n_limit / 2));    
            
            if (t < 1) t = 1;
            ns = rnd.partition(t, sum_n_limit, 2);
        }
    }

    
    cout << ns.size() << endl;

    for (int n : ns) {
        cout << n;
        if (mode == "adp") {
            
            
            cout << endl;
        } else {
            
            cout << endl;
            vector<int> p(n);
            iota(p.begin(), p.end(), 0);

            
            int pattern = rnd.next(100);
            
            
            if (seed_val == 3) pattern = (rnd.next(2) ? 80 : 90);

            if (pattern < 70) {
                
                shuffle(p.begin(), p.end());
            } else if (pattern < 80) {
                
                swap(p[0], p[rnd.next(n)]);
                int noise = rnd.next(0, 3);
                for (int k = 0; k < noise; ++k) 
                    swap(p[rnd.next(n)], p[rnd.next(n)]);
            } else if (pattern < 90) {
                
                int k = rnd.next(1, n - 1);
                for (int i = 0; i < n; ++i) p[i] = (i + k) % n;
            } else {
                
                
                shuffle(p.begin(), p.end());
                int pos0 = -1, pos1 = -1;
                for (int i = 0; i < n; ++i) {
                    if (p[i] == 0) pos0 = i;
                    if (p[i] == 1) pos1 = i;
                }
                int target = (pos0 + 1) % n;
                if (target != pos1) {
                    iter_swap(p.begin() + target, p.begin() + pos1);
                }
            }

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

    return 0;
}