Problem: cf1270_d
Difficulty: easy
Categories: data structures, math
Time limit: 1000 ms, memory limit: 256 MB

This problem is interactive.

We have hidden an array $a$ of $n$ pairwise different numbers (this means that no two numbers are equal). You can get some information about this array using a new device you just ordered on Amazon.

This device can answer queries of the following form: in response to the positions of $k$ different elements of the array, it will return the position and value of the $m$-th among them in the ascending order.

Unfortunately, the instruction for the device was lost during delivery. However, you remember $k$, but don't remember $m$. Your task is to find $m$ using queries to this device.

You can ask not more than $n$ queries.

Note that the array $a$ and number $m$ are fixed before the start of the interaction and don't depend on your queries. In other words, interactor is not adaptive.

Note that you don't have to minimize the number of queries, and you don't need to guess array $a$. You just have to guess $m$.

Input

The first line contains two integers $n$ and $k$ ($1\le k < n \le 500$) — the length of the array and the number of the elements in the query.

It is guaranteed that number $m$ satisfies $1\le m \le k$, elements $a_1, a_2, \dots, a_n$ of the array satisfy $0\le a_i \le 10^9$, and all of them are different.

Interaction

You begin the interaction by reading $n$ and $k$.

To ask a question about elements on positions $x_1, x_2, \dots, x_k$, in a separate line output

$?$ $x_1$ $x_2$ $x_3$ ... $x_k$

Numbers in the query have to satisfy $1 \le x_i \le n$, and all $x_i$ have to be different. Don't forget to 'flush', to get the answer.

In response, you will receive two integers $pos$ and $a_{pos}$ — the position in the array $a$ of the $m$-th in ascending order element among $a_{x_1}, a_{x_2}, \dots, a_{x_k}$, and the element on this position.

In case your query is invalid or you asked more than $n$ queries, the program will print $-1$ and will finish interaction. You will receive a Wrong answer verdict. Make sure to exit immediately to avoid getting other verdicts.

When you determine $m$, output

$!$ $m$

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

```
4 3
4 9
4 9
4 9
1 2
```

Output

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

Note

In the example, $n = 4$, $k = 3$, $m = 3$, $a = [2, 0, 1, 9]$.

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 readToken(string& tok) {
    return (cin >> tok) ? true : false;
}

static bool readIntFromCin(long long& x) {
    string s;
    if (!(cin >> s)) return false;
    if (s.empty()) return false;
    int i = 0;
    bool neg = false;
    if (s[0] == '-') {
        neg = true;
        i = 1;
        if ((int)s.size() == 1) return false;
    }
    long long val = 0;
    for (; i < (int)s.size(); ++i) {
        char c = s[i];
        if (c < '0' || c > '9') return false;
        val = val * 10 + (c - '0');
        if (val > (1LL << 62)) return false;
    }
    x = neg ? -val : val;
    return true;
}

static void replyInvalidQueryAndDie(const string& why) {
    cout << -1 << endl;
    cout.flush();
    finish(_wa, why);
}

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

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

    try {
        int n = inf.readInt(1, 500, "n");
        int k = inf.readInt(1, n - 1, "k");
        int m = inf.readInt(1, k, "m");

        vector<long long> a(n + 1);
        for (int i = 1; i <= n; ++i) {
            a[i] = inf.readLong(0LL, 1000000000LL, "a[i]");
        }

        query_limit = n;
        log_metrics(); 

        cout << n << " " << k << endl;
        cout.flush();

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

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

            if (cmd == "?") {
                if (queries >= hard_cap) finish(_pe, "hard cap exceeded");

                vector<int> xs;
                xs.reserve(k);
                vector<char> seen(n + 1, 0);

                for (int i = 0; i < k; ++i) {
                    long long xi_ll;
                    if (!readIntFromCin(xi_ll)) {
                        replyInvalidQueryAndDie("malformed index in query");
                    }
                    if (xi_ll < 1 || xi_ll > n) {
                        replyInvalidQueryAndDie("index out of range in query");
                    }
                    int xi = (int)xi_ll;
                    if (seen[xi]) {
                        replyInvalidQueryAndDie("duplicate index in query");
                    }
                    seen[xi] = 1;
                    xs.push_back(xi);
                }

                ++queries;
                log_metrics(); 

                vector<pair<long long, int>> vals;
                vals.reserve(k);
                for (int pos : xs) vals.push_back({a[pos], pos});
                sort(vals.begin(), vals.end()); 

                int ansPos = vals[m - 1].second;
                long long ansVal = vals[m - 1].first;

                cout << ansPos << " " << ansVal << endl;
                cout.flush();
            } else if (cmd == "!") {
                long long guess_ll;
                if (!readIntFromCin(guess_ll)) {
                    finish(_pe, "malformed final answer");
                }
                if (guess_ll < 1 || guess_ll > k) {
                    finish(_wa, "final answer out of range");
                }
                int guess = (int)guess_ll;
                if (guess == m) finish(_ok, "correct");
                finish(_wa, "wrong m");
            } else {
                if (cmd == "-1") finish(_pe, "contestant printed -1");
                finish(_pe, "unknown command token");
            }
        }
    } catch (const std::exception& e) {
        finish(_pe, string("exception: ") + e.what());
    } catch (...) {
        finish(_pe, "unknown exception");
    }
}


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 vector<int> buildArrayByRanks(int n, const vector<int>& rankAtPos) {
    vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i) {
        
        
        int base = rankAtPos[i] * 1000000;
        int add = rnd.next(0, 999999);
        a[i] = base + add;
    }
    return a;
}

static void genStructured(int n, int k, int m, vector<int>& outRankAtPos) {
    outRankAtPos.assign(n + 1, -1);

    if (k == 1) {
        
        int r = (n + 1) / 2;
        outRankAtPos[1] = r;
        int cur = 1;
        for (int x = 1; x <= n; ++x) {
            if (x == r) continue;
            ++cur;
            outRankAtPos[cur] = x;
        }
        return;
    }

    m = max(1, min(m, k));

    int minPivot = m;
    int maxPivot = n - (k - m);
    if (minPivot > maxPivot) {
        
        minPivot = maxPivot = max(1, min(n, m));
    }

    int mid = (n + 1) / 2;
    int pivotRank;
    
    if (mid < minPivot) pivotRank = minPivot;
    else if (mid > maxPivot) pivotRank = maxPivot;
    else pivotRank = mid;

    
    if (maxPivot - minPivot >= 4) {
        int delta = rnd.next(-2, 2);
        pivotRank = max(minPivot, min(maxPivot, pivotRank + delta));
    }

    vector<int> less, greater;
    less.reserve(max(0, pivotRank - 1));
    greater.reserve(max(0, n - pivotRank));

    for (int x = 1; x < pivotRank; ++x) less.push_back(x);
    for (int x = pivotRank + 1; x <= n; ++x) greater.push_back(x);

    shuffleVec(less);
    shuffleVec(greater);

    int needLess = m - 1;
    int needGreater = k - m;

    
    if (needLess > (int)less.size()) {
        int deficit = needLess - (int)less.size();
        needLess -= deficit;
        needGreater += deficit;
        needGreater = min(needGreater, (int)greater.size());
    }
    if (needGreater > (int)greater.size()) {
        int deficit = needGreater - (int)greater.size();
        needGreater -= deficit;
        needLess += deficit;
        needLess = min(needLess, (int)less.size());
    }

    vector<int> firstK;
    firstK.reserve(k);

    for (int i = 0; i < needLess; ++i) firstK.push_back(less[i]);
    firstK.push_back(pivotRank);
    for (int i = 0; i < needGreater; ++i) firstK.push_back(greater[i]);

    while ((int)firstK.size() < k) {
        
        if ((int)greater.size() > needGreater) {
            firstK.push_back(greater[needGreater]);
            ++needGreater;
        } else if ((int)less.size() > needLess) {
            firstK.push_back(less[needLess]);
            ++needLess;
        } else {
            break;
        }
    }

    shuffleVec(firstK);

    vector<int> used(n + 1, 0);
    for (int x : firstK) used[x] = 1;

    vector<int> rest;
    rest.reserve(n - k);
    for (int x = 1; x <= n; ++x) if (!used[x]) rest.push_back(x);
    shuffleVec(rest);

    for (int i = 1; i <= k; ++i) outRankAtPos[i] = firstK[i - 1];
    for (int i = k + 1; i <= n; ++i) outRankAtPos[i] = rest[i - (k + 1)];
}

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

    string mode = opt<string>("mode", "non");

    long long seed = 0;
    if (argc >= 2) {
        
        seed = atoll(argv[1]);
    }

    int n = opt<int>("n", 500);
    n = max(2, min(500, n));

    int kOpt = opt<int>("k", 0);
    int k;
    if (kOpt != 0) {
        k = kOpt;
    } else {
        
        if (seed >= 4 && (seed % 5 == 0)) k = 2;
        else if (seed >= 4 && (seed % 7 == 0)) k = 3;
        else k = (n / 2);
    }
    k = max(1, min(n - 1, k));

    int mOpt = opt<int>("m", 0);
    int m;
    if (mOpt != 0) {
        m = mOpt;
    } else {
        if (seed == 1) m = 1;
        else if (seed == 2) m = k; 
        else if (seed == 3) m = max(1, min(k, (k + 1) / 2)); 
        else {
            if (k == 1) m = 1;
            else {
                
                int t = rnd.next(0, 9);
                if (t == 0) m = 1;
                else if (t == 1) m = k;
                else {
                    int mid = (k + 1) / 2;
                    int delta = (k >= 6 ? rnd.next(-2, 2) : rnd.next(-1, 1));
                    m = max(1, min(k, mid + delta));
                    if (k >= 3 && m == 1) m = 2;
                    if (k >= 3 && m == k) m = k - 1;
                }
            }
        }
    }
    m = max(1, min(k, m));

    
    vector<int> a;
    if (seed == 1) {
        n = 2; k = 1; m = 1;
        a.assign(n + 1, 0);
        a[1] = 0;
        a[2] = 1;
    } else if (seed == 2) {
        n = 500; k = 499; m = 499;
        a.assign(n + 1, 0);
        for (int i = 1; i <= n; ++i) a[i] = i; 
    } else if (seed == 3) {
        n = 500; k = 250; m = 125;
        vector<int> rankAtPos;
        genStructured(n, k, m, rankAtPos);
        a = buildArrayByRanks(n, rankAtPos);
    } else {
        
        
        vector<int> rankAtPos;
        genStructured(n, k, m, rankAtPos);
        a = buildArrayByRanks(n, rankAtPos);
    }

    if (mode != "non" && mode != "adp") {
        quitf(_fail, "unknown mode: %s", mode.c_str());
    }

    cout << n << " " << k << "\n";
    cout << m << "\n";
    if (mode == "non") {
        for (int i = 1; i <= n; ++i) {
            if (i > 1) cout << ' ';
            cout << a[i];
        }
        cout << "\n";
    }
    return 0;
}