Problem: cf1423_m
Difficulty: medium
Categories: search
Time limit: 1000 ms, memory limit: 1024 MB

As you all know, the plum harvesting season is on! Little Milutin had his plums planted in an orchard that can be represented as an $n$ by $m$ matrix. While he was harvesting, he wrote the heights of all trees in a matrix of dimensions $n$ by $m$.

At night, when he has spare time, he likes to perform various statistics on his trees. This time, he is curious to find out the height of his lowest tree. So far, he has discovered some interesting properties of his orchard. There is one particular property that he thinks is useful for finding the tree with the smallest heigh.

Formally, let $L(i)$ be the leftmost tree with the smallest height in the $i$-th row of his orchard. He knows that $L(i) \le L(i+1)$ for all $1 \le i \le n - 1$. Moreover, if he takes a submatrix induced by any subset of rows and any subset of columns, $L(i) \le L(i+1)$ will hold for all $1 \le i \le n'-1$, where $n'$ is the number of rows in that submatrix.

Since the season is at its peak and he is short on time, he asks you to help him find the plum tree with minimal height.

Input

This problem is interactive.

The first line of input will contain two integers $n$ and $m$, representing the number of rows and the number of columns in Milutin's orchard. It is guaranteed that $1 \le n, m \le 10^6$.

The following lines will contain the answers to your queries.

Output

Once you know have found the minimum value $r$, you should print ! $r$ to the standard output.

Interaction

Your code is allowed to query for an entry $(i, j)$ of a matrix (i.e. get the height of the tree which is in the $i$-th row and $j$-th column). The query should be formatted as ? $i$ $j$, so that $1 \le i \le n$ and $1 \le j \le m$.

You may assume that the entries of the matrix will be integers between $1$ and $10^9$.

Your solution should use not more than $\mathbf{4 \cdot (n + m)}$ queries.

This is an interactive problem. You have to use a flush operation right after printing each line. For example, in C++ you should use the function fflush(stdout), in Java — System.out.flush(), in Pascal — flush(output) and in Python — sys.stdout.flush().

Example

Input

```
5 5
13 15 10 9 15
15 17 12 11 17
10 12 7 6 12
17 19 14 13 19
16 18 13 12 18
```

Output

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) {
    if (!(cin >> tok)) return false;
    return true;
}

static bool parseLongLongStrict(const string& s, long long& out) {
    if (s.empty()) return false;
    int i = 0;
    if (s[0] == '+') i++;
    if (i >= (int)s.size()) return false;
    if (s[i] == '-') return false;
    long long val = 0;
    for (; i < (int)s.size(); i++) {
        unsigned char c = (unsigned char)s[i];
        if (!isdigit(c)) return false;
        int d = s[i] - '0';
        if (val > (LLONG_MAX - d) / 10) return false;
        val = val * 10 + d;
    }
    out = val;
    return true;
}

static bool parseBoundedIntToken(const string& s, long long lo, long long hi, long long& out) {
    long long v;
    if (!parseLongLongStrict(s, v)) return false;
    if (v < lo || v > hi) return false;
    out = v;
    return true;
}



static struct _BumpTestlibLimits {
    _BumpTestlibLimits() {
        inf.maxFileSize = 512ULL * 1024ULL * 1024ULL; 
    }
} _bumpTestlibLimits;

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

    int n = 0, m = 0;
    try {
        n = inf.readInt(1, 1000000, "n");
        m = inf.readInt(1, 1000000, "m");
    } catch (...) {
        query_limit = 0;
        log_metrics();
        quitf(_pe, "Invalid hidden input (failed to read n,m)");
    }

    query_limit = 4LL * ( (long long)n + (long long)m );
    log_metrics(); 

    long long nm = 1LL * n * m;
    vector<int> a;
    a.reserve((size_t)min<long long>(nm, 1000000LL));

    int globalMin = INT_MAX;
    try {
        a.assign((size_t)nm, 0);
        for (int i = 1; i <= n; i++) {
            long long base = 1LL * (i - 1) * m;
            for (int j = 1; j <= m; j++) {
                int v = inf.readInt(1, 1000000000, "a[i][j]");
                a[(size_t)(base + (j - 1))] = v;
                if (v < globalMin) globalMin = v;
            }
        }
    } catch (const bad_alloc&) {
        finish(_pe, "Interactor out of memory while storing matrix");
    } catch (...) {
        finish(_pe, "Invalid hidden input (failed to read full matrix)");
    }

    
    cout << n << " " << m << endl;

    const long long hard_cap = max(200000LL, query_limit > (LLONG_MAX / 10) ? LLONG_MAX : 10LL * query_limit);

    while (true) {
        string cmd;
        if (!readToken(cmd)) {
            finish(_pe, "Unexpected EOF: contestant did not output final answer");
        }

        if (cmd == "?") {
            string si, sj;
            if (!readToken(si) || !readToken(sj)) {
                finish(_pe, "Malformed query: expected '? i j'");
            }
            long long i, j;
            if (!parseBoundedIntToken(si, 1, n, i) || !parseBoundedIntToken(sj, 1, m, j)) {
                finish(_pe, "Query indices out of bounds or not integers");
            }

            queries++;
            if (queries > hard_cap) {
                finish(_pe, "Hard cap exceeded (too many queries/output spam)");
            }

            int ans = a[(size_t)((i - 1) * 1LL * m + (j - 1))];
            cout << ans << endl;
        } else if (cmd == "!") {
            string sr;
            if (!readToken(sr)) {
                finish(_pe, "Malformed answer: expected '! r'");
            }
            long long r;
            if (!parseBoundedIntToken(sr, 1, 1000000000LL, r)) {
                finish(_pe, "Answer is not a valid integer in [1,1e9]");
            }
            if ((int)r == globalMin) {
                finish(_ok, "Correct");
            } else {
                finish(_wa, "Wrong minimum");
            }
        } else {
            finish(_pe, "Unknown command (expected '?' or '!')");
        }
    }
}


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 isIntegerToken(const string& s) {
    if (s.empty()) return false;
    int i = 0;
    if (s[0] == '-') {
        if ((int)s.size() == 1) return false;
        i = 1;
    }
    for (; i < (int)s.size(); i++) if (!isdigit((unsigned char)s[i])) return false;
    return true;
}

struct AdaptiveSchema {
    int n = 0, m = 0;
    int type = 0; 
    int g = 0;
    vector<int> p; 
    vector<long long> B, D; 
    uint64_t baseSeed = 0x123456789abcdefULL;
};

static uint64_t splitmix64(uint64_t x) {
    x += 0x9e3779b97f4a7c15ULL;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;
    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;
    return x ^ (x >> 31);
}

static long long noiseDet(const AdaptiveSchema& S, int i, int j) {
    
    uint64_t x = S.baseSeed;
    x ^= (uint64_t)i * 1000003ULL;
    x ^= (uint64_t)j * 10007ULL;
    x = splitmix64(x);
    return (long long)(x & 7ULL);
}

static long long valueAt(const AdaptiveSchema& S, int i, int j) {
    
    int idx = i - 1;
    int p = S.p[idx];
    long long minVal = S.B[idx] - S.D[idx];
    if (minVal < 1) minVal = 1;
    long long dist = llabs((long long)j - p);
    long long v = minVal + dist * dist * 5 + dist * 13 + noiseDet(S, i, j);

    
    if (j == p) v = minVal;
    if (j < p && v <= minVal) v = minVal + 1;

    
    if (i == S.g && j == S.p[S.g - 1]) v = 1;

    if (v < 1) v = 1;
    if (v > 1000000000LL) v = 1000000000LL - (v % 1000);
    if (v < 1) v = 1;
    return v;
}

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

    int n = 0, m = 0;
    if (inf.seekEof()) finish(_pe, "empty input");
    n = inf.readInt(1, 1000000, "n");
    m = inf.readInt(1, 1000000, "m");

    
    
    
    if (inf.seekEof()) finish(_pe, "no data after n m");

    
    string tok = inf.readToken();
    bool adaptive = false;
    int type = 0;

    if (isIntegerToken(tok)) {
        long long maybeTypeOrA11 = stoll(tok);
        if (maybeTypeOrA11 == 1) {
            
            
            
            
            
            
            
            adaptive = true;
            type = 1;
        } else {
            adaptive = false;
        }
    } else {
        finish(_pe, "unexpected token after n m");
    }

    
    query_limit = 4LL * ( (long long)n + (long long)m );
    log_metrics(); 
    long long hard_cap = max(200000LL, 10LL * query_limit);

    AdaptiveSchema S;
    vector<vector<int>> A; 
    bool nonLoaded = false;

    if (adaptive) {
        
        
        
        if (inf.seekEof()) {
            adaptive = false;
        } else {
            int g = 0;
            try {
                g = inf.readInt(1, n, "g");
            } catch (...) {
                adaptive = false;
            }
            if (adaptive) {
                S.n = n; S.m = m; S.type = type; S.g = g;
                S.p.assign(n, 1);
                S.B.assign(n, 0);
                S.D.assign(n, 0);
                bool ok = true;
                for (int i = 1; i <= n; i++) {
                    if (inf.seekEof()) { ok = false; break; }
                    int pi;
                    long long Bi, Di;
                    try {
                        pi = inf.readInt(1, m, "p[i]");
                        Bi = inf.readLong(1LL, 1000000000LL, "B[i]");
                        Di = inf.readLong(0LL, 1000000000LL, "D[i]");
                    } catch (...) {
                        ok = false; break;
                    }
                    if (Di >= Bi) { ok = false; break; }
                    if (Bi - Di < 1) { ok = false; break; }
                    S.p[i-1] = pi;
                    S.B[i-1] = Bi;
                    S.D[i-1] = Di;
                }
                if (!ok) adaptive = false;
                else {
                    
                    uint64_t h = 1469598103934665603ULL;
                    auto mix = [&](uint64_t x) {
                        h ^= x + 0x9e3779b97f4a7c15ULL + (h<<6) + (h>>2);
                    };
                    mix((uint64_t)n); mix((uint64_t)m); mix((uint64_t)type); mix((uint64_t)g);
                    for (int i = 0; i < n; i++) {
                        mix((uint64_t)S.p[i]);
                        mix((uint64_t)S.B[i]);
                        mix((uint64_t)S.D[i]);
                    }
                    S.baseSeed = splitmix64(h);
                }
            }
        }
    }

    if (!adaptive) {
        
        
        
        
        
        long long cells = 1LL * n * m;
        if (cells > 25000000LL) { 
            finish(_pe, "non-adaptive matrix too large to store in interactor");
        }
        A.assign(n, vector<int>(m, 0));
        
        if (!isIntegerToken(tok)) finish(_pe, "invalid a11 token");
        long long a11 = stoll(tok);
        if (a11 < 1 || a11 > 1000000000LL) finish(_pe, "a11 out of range");
        A[0][0] = (int)a11;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (i==0 && j==0) continue;
                if (inf.seekEof()) finish(_pe, "not enough matrix entries");
                int v = inf.readInt(1, 1000000000, "a[i][j]");
                A[i][j] = v;
            }
        }
        nonLoaded = true;
    }

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

    auto getVal = [&](int i, int j)->long long{
        if (adaptive) return valueAt(S, i, j);
        else return A[i-1][j-1];
    };

    
    while (true) {
        string cmd;
        if (!(cin >> cmd)) {
            finish(_pe, "EOF from contestant");
        }
        if (cmd == "?") {
            long long i, j;
            if (!(cin >> i >> j)) finish(_pe, "bad query format");
            if (i < 1 || i > n || j < 1 || j > m) finish(_pe, "query indices out of range");

            queries++;
            if (queries > hard_cap) finish(_pe, "too many queries (hard cap exceeded)");

            long long ans = getVal((int)i, (int)j);
            cout << ans << "\n";
            cout.flush();
        } else if (cmd == "!") {
            long long r;
            if (!(cin >> r)) finish(_pe, "bad answer format");
            if (r < 1 || r > 1000000000LL) finish(_wa, "answer out of range");

            
            long long trueMin = LLONG_MAX;
            if (adaptive) {
                
                
                trueMin = 1;
                for (int i = 1; i <= n; i++) {
                    long long mv = S.B[i-1] - S.D[i-1];
                    if (mv < 1) mv = 1;
                    
                    trueMin = min(trueMin, mv);
                }
            } else {
                for (int i = 0; i < n; i++)
                    for (int j = 0; j < m; j++)
                        trueMin = min(trueMin, (long long)A[i][j]);
            }

            if (r != trueMin) finish(_wa, "wrong minimum");
            finish(_ok, "ok");
        } else {
            finish(_pe, "unknown command");
        }
    }
}


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

static long long INFLL = (1LL<<62);

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

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

    
    
    int n = opt<int>("n", 4000);
    int m = opt<int>("m", 4000);

    
    n = max(1, min(n, 1000000));
    m = max(1, min(m, 1000000));

    int seed = 1;
    if (argc >= 2) {
        
        
        try {
            seed = stoi(string(argv[1]));
        } catch (...) {
            seed = 1;
        }
    }

    if (mode == "non") {
        
        
        

        
        if (seed == 1) {
            
            n = 6; m = 7;
            cout << n << " " << m << "\n";
            
            
            vector<vector<int>> a = {
                {50, 40, 30, 20, 21, 22, 23}, 
                {60, 41, 31, 19, 19, 24, 25}, 
                {70, 42, 18, 18, 26, 27, 28}, 
            };
            
            a = {
                {50, 40, 30, 20, 21, 22, 23}, 
                {60, 41, 31, 19, 19, 24, 25}, 
                {70, 42, 32, 18, 18, 27, 28}, 
                {80, 43, 33, 17, 29, 30, 31}, 
                {90, 44, 34, 16, 16, 32, 33}, 
                {100,45, 35, 16, 34, 35, 36}  
            };
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if (j) cout << ' ';
                    cout << a[i][j];
                }
                cout << "\n";
            }
            return 0;
        } else if (seed == 2) {
            
            n = 3; m = 12;
            cout << n << " " << m << "\n";
            vector<vector<int>> a(n, vector<int>(m, 1000000000));
            
            for (int j = 0; j < m; j++) a[0][j] = 500 + j;
            a[0][1] = 1;
            
            for (int j = 0; j < m; j++) a[1][j] = 800 + 3*j;
            a[1][6] = 2;
            
            for (int j = 0; j < m; j++) a[2][j] = 900 + 2*j;
            a[2][10] = 3;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if (j) cout << ' ';
                    cout << a[i][j];
                }
                cout << "\n";
            }
            return 0;
        } else if (seed == 3) {
            
            n = 1; m = 20;
            cout << n << " " << m << "\n";
            
            for (int j = 1; j <= m; j++) {
                long long v = 1000 + (j-1)*7;
                if (j == 9 || j == 15) v = 5;
                if (j == 20) v = 6;
                if (j > 1) cout << ' ';
                cout << v;
            }
            cout << "\n";
            return 0;
        }

        
        
        
        
        
        
        int maxN = opt<int>("maxn", 6000);
        int maxM = opt<int>("maxm", 6000);
        n = min(n, maxN);
        m = min(m, maxM);
        if (n <= 0) n = 4000;
        if (m <= 0) m = 4000;

        cout << n << " " << m << "\n";

        
        vector<int> pos(n);
        int cur = rnd.next(1, max(1, m));
        for (int i = 0; i < n; i++) {
            
            int jump = rnd.next(0, 9);
            if (jump <= 2) {
                
                cur = min(m, cur + rnd.next(0, 3));
            } else if (jump == 3) {
                
                cur = min(m, cur + rnd.next(10, 50));
            } else {
                
                cur = cur;
            }
            if (cur < 1) cur = 1;
            if (cur > m) cur = m;
            pos[i] = cur;
        }

        
        int gi = rnd.next(max(1, n - max(1, n/10)), n); 
        int gj = pos[gi-1];
        
        
        (void)gj;

        
        
        
        for (int i = 1; i <= n; i++) {
            int p = pos[i-1]; 
            
            long long base = 300000000LL + 1000LL * i;
            
            long long depth = rnd.next(100000LL, 500000LL);
            
            long long minVal = max(1LL, base - depth);

            
            
            
            
            
            for (int j = 1; j <= m; j++) {
                long long dist = llabs((long long)j - p);
                
                long long v = minVal + dist * dist * 5 + dist * 13;
                
                long long noise = rnd.next(0LL, 7LL);
                v += noise;

                
                if (j == p) v = minVal;
                if (j < p) v = max(v, minVal + 1); 
                
                if (j > p && rnd.next(0, 99) < 2) v = minVal + rnd.next(0LL, 3LL);

                
                if (i == gi && j == p) v = 1;

                
                if (v > 1000000000LL) v = 1000000000LL - (v % 1000);
                if (v < 1) v = 1;

                if (j > 1) cout << ' ';
                cout << v;
            }
            cout << "\n";
        }

        return 0;
    } else if (mode == "adp") {
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        

        
        if (seed == 1) { n = 5; m = 5; }
        if (seed == 2) { n = 2; m = 10; }
        if (seed == 3) { n = 10; m = 1; }

        cout << n << " " << m << "\n";
        cout << 1 << "\n"; 

        vector<int> p(n);
        int cur = rnd.next(1, m);
        for (int i = 0; i < n; i++) {
            int t = rnd.next(0, 9);
            if (t <= 2) cur = min(m, cur + rnd.next(0, 2));
            else if (t == 3) cur = min(m, cur + rnd.next(5, 30));
            p[i] = max(1, min(m, cur));
        }

        int g = rnd.next(max(1, n - max(1, n/10)), n);

        cout << g << "\n";
        for (int i = 1; i <= n; i++) {
            long long B = 300000000LL + 1000LL * i + rnd.next(0LL, 10000LL);
            long long D = rnd.next(100000LL, 600000LL);
            if (D >= B) D = B - 1;
            cout << p[i-1] << " " << B << " " << D << "\n";
        }
        return 0;
    } else {
        
        n = 1; m = 1;
        cout << n << " " << m << "\n";
        cout << 1 << "\n";
        return 0;
    }
}