Problem: cf2162_d
Difficulty: medium
Categories: search, math
Time limit: 2000 ms, memory limit: 256 MB

This is an interactive problem.

There is a permutation$^{\text{∗}}$ $p$ of length $n$.

Someone secretly chose two integers $l, r$ ($1 \le l \le r \le n$) and modified the permutation in the following way:

* For every index $i$ such that $l \le i \le r$, set $p_i := p_i + 1$.

Let $a$ denote the resulting array obtained by modifying the permutation.

You are given an integer $n$ denoting the length of the permutation $p$.

In one query, you are allowed to choose two integers $l, r$ ($1 \le l \le r \le n$) and ask for the sum of the subarray either of the original permutation $p[l \dots r]$ or of the modified array $a[l \dots r]$. The answer to such a query will be the corresponding integer sum.

Your task is to find the pair $(l, r)$ that was chosen to obtain $a$ in no more than $\bf{40}$ queries.

$^{\text{∗}}$A permutation of length $n$ is an array consisting of $n$ distinct integers from $1$ to $n$ in any order. For example, $[2,3,1,5,4]$ is a permutation, but $[1,2,2]$ is not a permutation (the number $2$ appears twice in the array), and $[1,3,4]$ is also not a permutation ($n=3$, but the array contains $4$).

Input

The first line of input contains a single integer $t$ ($1 \le t \le 10^4$) — the number of test cases.

Each test case contains a single integer $n$ ($1 \le n \le 2\cdot10^4$) — the length of the permutation.

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

Interaction

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

You can ask two types of queries.

* Print "$ \texttt{1 l r} $" ($1 \le l \le r \le n$).

  In response, you should read a line containing a single integer $x$ — the sum of the subarray of the original permutation. (Formally, $x = p_l + p_{l + 1} + \dots + p_r$).
* Print "$ \texttt{2 l r} $" ($1 \le l \le r \le n$).

  In response, you should read a line containing a single integer $y$ — the sum of the subarray of the modified array. (Formally, $y = a_l + a_{l + 1} + \dots + a_r$).

The permutation $p$ and the chosen integers $l$, $r$ are fixed beforehand and can't be changed during the time of interaction.

You can output the final answer by printing "$ \texttt{! l r} $", where $l$, $r$ denote the integers that were chosen to obtain $a$. After printing the answer, your program should proceed to the next test case or terminate if there are no more.

You can ask no more than $40$ queries per testcase. Printing the answer doesn't count as a query. If your program performs more than $40$ queries for one test case or makes an invalid query, you may receive a Wrong Answer verdict.

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

Example

Input

```
2

3

4

5

4

8

8

9
```

Output

```
1 1 2

2 1 2

! 2 2

1 2 4

2 1 3

2 3 4

! 2 4
```

Note

For the first testcase, $p = [3, 1, 2]$ and $l = 2$, $r = 2$. Hence, the modified array $a$ will be equal to $[3, 2, 2]$.

So, querying "$\texttt{1 1 2}$" gives $p_1 + p_2 = 3 + 1 = 4$. And querying "$\texttt{2 1 2}$" gives $a_1 + a_2 = 3 + 2 = 5$.

For the second testcase, $p = [2, 1, 3, 4]$ and $l = 2$, $r = 4$.

Note that the queries shown in the sample test are only for demonstration purposes, and they may not correspond to any optimal solution.

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



static long long max_queries = 0;
static const long long QUERY_LIMIT_PER_CASE = 40;



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


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

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

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

    for (int t = 1; t <= T; ++t) {
        
        int n = inf.readInt();
        vector<int> p(n + 1);
        vector<long long> pref_p(n + 1, 0);
        for (int i = 1; i <= n; ++i) {
            p[i] = inf.readInt();
            pref_p[i] = pref_p[i-1] + p[i];
        }
        int L_ans = inf.readInt();
        int R_ans = inf.readInt();

        
        cout << n << endl;

        int current_queries = 0;
        bool solved = false;

        
        while (true) {
            
            
            
            if (current_queries > 2000) {
                finish(_pe, "Too many queries (hard cap hit)");
            }

            string token;
            if (!(cin >> token)) {
                finish(_wa, "Unexpected EOF (contestant terminated early)");
            }

            
            if (token == "!") {
                int l_sub, r_sub;
                if (!(cin >> l_sub >> r_sub)) {
                    finish(_wa, "Invalid answer format after '!'");
                }
                
                
                if (l_sub != L_ans || r_sub != R_ans) {
                    finish(_wa, format("Incorrect answer for testcase %d. Expected %d %d, got %d %d", t, L_ans, R_ans, l_sub, r_sub));
                }
                
                
                solved = true;
                break; 
            }

            
            int type, l, r;
            if (token == "?") {
                if (!(cin >> type >> l >> r)) {
                    finish(_wa, "Invalid query format after '?'");
                }
            } else {
                
                try {
                    type = stoi(token);
                } catch (...) {
                    finish(_wa, "Invalid token (expected query type or '!')");
                }
                if (!(cin >> l >> r)) {
                    finish(_wa, "Invalid query parameters");
                }
            }

            
            if (type != 1 && type != 2) {
                finish(_wa, format("Invalid query type %d", type));
            }
            if (l < 1 || r > n || l > r) {
                finish(_wa, format("Invalid range [%d, %d] with n=%d", l, r, n));
            }

            
            current_queries++;
            if (current_queries > max_queries) {
                max_queries = current_queries;
            }
            
            if (current_queries % 10 == 0) {
                log_metrics();
            }

            
            long long ans = 0;
            
            long long sum_p = pref_p[r] - pref_p[l-1];

            if (type == 1) {
                
                ans = sum_p;
            } else {
                
                
                
                int intersect_l = max(l, L_ans);
                int intersect_r = min(r, R_ans);
                int count = 0;
                if (intersect_l <= intersect_r) {
                    count = intersect_r - intersect_l + 1;
                }
                ans = sum_p + count;
            }

            
            cout << ans << endl;
        }

        if (!solved) {
            finish(_wa, "Loop terminated without answer");
        }
    }

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


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

using namespace std;


static long long max_queries = 0;
static const long long QUERY_LIMIT_PER_CASE = 40;



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


static void finish(TResult verdict, const string& msg) {
    if (verdict != _ok) {
        cout << -1 << endl;
        cout.flush();
    }
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}


static void my_atexit() {
    log_metrics();
}

static void solve_one(int n) {
    
    
    vector<int> p = rnd.perm(n, 1);

    vector<long long> pref(n + 1, 0);
    for (int i = 1; i <= n; i++) pref[i] = pref[i - 1] + p[i - 1];

    int L = 1, R = 1;
    if (rnd.next(5) == 0) {
        
        int type = rnd.next(5);
        if (type == 0) { L = 1; R = n; }                  
        else if (type == 1) { L = 1; R = rnd.next(1, n); } 
        else if (type == 2) { R = n; L = rnd.next(1, n); } 
        else if (type == 3) { L = rnd.next(1, n); R = L; } 
        else {                                              
            if (n > 1) { L = rnd.next(1, n - 1); R = L + 1; }
            else { L = 1; R = 1; }
        }
    } else {
        L = rnd.next(1, n);
        R = rnd.next(1, n);
        if (L > R) swap(L, R);
    }

    int used = 0;
    while (true) {
        string tok;
        if (!(cin >> tok)) finish(_wa, "Unexpected EOF");

        if (tok == "!") {
            int l, r;
            if (!(cin >> l >> r)) finish(_wa, "Malformed answer");
            if (l == L && r == R) return;
            finish(_wa, format("Wrong answer (expected %d %d, got %d %d)", L, R, l, r));
        }

        int type = -1;
        if (tok == "1") type = 1;
        else if (tok == "2") type = 2;
        else finish(_wa, "Invalid token (expected '1', '2', or '!')");

        int l, r;
        if (!(cin >> l >> r)) finish(_wa, "Malformed query");
        if (l < 1 || r > n || l > r) finish(_wa, format("Invalid range [%d,%d] (n=%d)", l, r, n));

        used++;
        if (used > (int)QUERY_LIMIT_PER_CASE) finish(_wa, "Query limit exceeded (40 per testcase)");
        max_queries = max<long long>(max_queries, used);
        if (used % 10 == 0) log_metrics();

        long long sum_p = pref[r] - pref[l - 1];
        if (type == 1) {
            cout << sum_p << endl;
            cout.flush();
            continue;
        }

        int il = max(l, L);
        int ir = min(r, R);
        long long add = (il <= ir) ? (ir - il + 1) : 0;
        cout << (sum_p + add) << endl;
        cout.flush();
    }
}

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

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

    for (int i = 0; i < t; ++i) {
        int n = inf.readInt();
        cout << n << endl; 
        cout.flush();
        solve_one(n);
    }

    finish(_ok, "All test 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 opt_t = opt<int>("t", -1);
    int opt_n = opt<int>("n", -1);

    const int MAX_SUM_N = 20000;
    vector<int> ns;

    
    bool custom = (opt_t != -1 || opt_n != -1);

    if (!custom) {
        
        string seedStr = (argc > 1 ? argv[1] : "1");

        if (seedStr == "1") {
            
            ns = {MAX_SUM_N};
        } else if (seedStr == "2") {
            
            ns.assign(10000, 2);
        } else if (seedStr == "3") {
            
            int rem = MAX_SUM_N;
            while (rem > 0) {
                int cur = rnd.next(10, 500);
                if (cur > rem) cur = rem;
                ns.push_back(cur);
                rem -= cur;
            }
        } else {
            
            int total_n = rnd.next(1, MAX_SUM_N);
            int t = 1;
            if (total_n > 1) {
                int type = rnd.next(10);
                if (type < 5) {
                    t = 1;
                } else if (type < 8) {
                    
                    t = rnd.next(2, min(total_n, 10));
                } else {
                    
                    int low = min(total_n, 10);
                    int high = min(total_n, 100);
                    t = rnd.next(low, high);
                }
            }
            ns = rnd.partition(t, total_n, 1);
        }
    } else {
        
        int S = (opt_n == -1) ? MAX_SUM_N : opt_n;
        int T = (opt_t == -1) ? -1 : opt_t;
        
        
        if (T == -1) {
            if (S > 5000) T = 1;
            else T = rnd.next(1, min(S, 10));
        }
        
        
        if (T > S) T = S;
        if (T < 1) T = 1;
        
        ns = rnd.partition(T, S, 1);
    }

    
    println(ns.size());

    
    for (int n : ns) {
        if (mode == "non") {
            println(n);
            vector<int> p = rnd.perm(n, 1);
            println(p);

            int l, r;
            
            if (rnd.next(5) == 0) {
                int type = rnd.next(5);
                if (type == 0) { l = 1; r = n; } 
                else if (type == 1) { l = 1; r = rnd.next(1, n); } 
                else if (type == 2) { r = n; l = rnd.next(1, n); } 
                else if (type == 3) { l = rnd.next(1, n); r = l; } 
                else { 
                    if (n > 1) { l = rnd.next(1, n-1); r = l + 1; }
                    else { l = 1; r = 1; }
                }
            } else {
                
                l = rnd.next(1, n);
                r = rnd.next(1, n);
                if (l > r) swap(l, r);
            }
            println(l, r);
        } else {
            
            println(n);
        }
    }

    return 0;
}