Problem: cf2174_e2
Difficulty: hard
Categories: math
Time limit: 2000 ms, memory limit: 1024 MB

The two versions have different constraints on $k$, $c$. Solving one of the two versions does not necessarily solve the other. You may want to read both versions.

This is an interactive problem.

During the time of the Ottoman Empire, many scientists were at work. You decided to study their daily life and stumbled upon an interesting game that was popular at that time. One scientist would think of an integer $x$, such that $1 \leq x \leq c$. Another scientist would try to guess it. He could specify the base of the numeral system $2 \leq b \leq c$ and would receive as a response the sum of the digits of the number $x$ in base $b$, if $x \geq b$, or $-1$ if $x < b$.

You wrote a program that can think of a number $x$ and respond to the question. Now you want to play with it and learn to guess using $\leq k$ queries.

Input

The first line contains three integers $t$, $k$, $c$ ($1 \leq t \leq 10^4$, $\mathbf{k=3}$, $\mathbf{c=2\cdot10^9}$). You must guess the number from $1$ to $c$ $t$ times, using $\leq k$ queries. All $t$ games will be played consecutively and are independent.

Interaction

To make a query, you must output ? $b$ for some $2 \leq b \leq c$. Then you must read the response — an integer $a$ ($-1 \leq a < c$) — the response to the query.

To provide the guessed number, you must output ! $x$, where $1 \leq x \leq c$ — your answer. Then you must read the result $r$ ($0 \leq r \leq 1$). If $r = 0$ — your answer is incorrect, you must immediately terminate the program in this case. Otherwise, if $r = 1$ — your answer is correct, you can proceed to the next game or terminate the program if $t$ games have already been played.

It is guaranteed that the interactor is not adaptive. That is, all chosen numbers are fixed in advance and do not change during the games.

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 -2 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

```
3 3 2000000000

1

1

7

1

-1

1

-1

6

6

1
```

Output

```
? 10

? 1000

? 2

! 1000000

? 2

! 1

? 100

? 10

? 5

! 42
```

Note

In the first game, the hidden number is $1000000_{10} = 100_{1000} = 11110100001001000000_2$. The sums of digits are $1$, $1$, and $7$ in these bases.

In the second game, the hidden number is $1$. The query with $b = 2$ returns $-1$.

In the third game, the hidden number is $42_{10} = 132_{5}$.

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& s) {
    s.clear();
    if (!(cin >> s)) return false;
    return true;
}

static bool parseLongLongStrict(const string& s, long long& out) {
    if (s.empty()) return false;
    int i = 0;
    if (s[0] == '+' || s[0] == '-') i = 1;
    if (i == (int)s.size()) return false;
    for (; i < (int)s.size(); i++) {
        if (s[i] < '0' || s[i] > '9') return false;
    }
    try {
        size_t pos = 0;
        long long v = stoll(s, &pos, 10);
        if (pos != s.size()) return false;
        out = v;
        return true;
    } catch (...) {
        return false;
    }
}

static long long digitSumBase(long long x, long long b) {
    long long sum = 0;
    while (x > 0) {
        sum += x % b;
        x /= b;
    }
    return sum;
}

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

    try {
        int t = inf.readInt(1, 10000, "t");
        int k = inf.readInt(1, 10, "k");
        long long c = inf.readLong(2, 2000000000LL, "c");

        query_limit = 1LL * t * k;
        log_metrics(); 

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

        cout << t << " " << k << " " << c << "\n";
        cout.flush();

        for (int game = 0; game < t; game++) {
            long long hidden = inf.readLong(1, c, "x");

            while (true) {
                string op;
                if (!readToken(op)) finish(_pe, "Unexpected EOF from contestant.");

                if (op == "?") {
                    string sb;
                    if (!readToken(sb)) finish(_pe, "Missing base after '?'.");

                    long long b;
                    if (!parseLongLongStrict(sb, b)) finish(_pe, "Base is not an integer.");
                    if (b < 2 || b > c) finish(_pe, "Base out of range.");

                    queries++;
                    if (queries > hard_cap) finish(_pe, "Hard cap exceeded.");

                    long long ans = (hidden < b) ? -1 : digitSumBase(hidden, b);
                    cout << ans << "\n";
                    cout.flush();
                } else if (op == "!") {
                    string sx;
                    if (!readToken(sx)) finish(_pe, "Missing number after '!'.");

                    long long guess;
                    if (!parseLongLongStrict(sx, guess)) finish(_pe, "Guess is not an integer.");
                    if (guess < 1 || guess > c) finish(_pe, "Guess out of range.");

                    int ok = (guess == hidden) ? 1 : 0;
                    cout << ok << "\n";
                    cout.flush();

                    if (!ok) finish(_wa, "Wrong guess.");
                    break; 
                } else {
                    finish(_pe, "Invalid operation token (expected '?' or '!').");
                }
            }
        }

        finish(_ok, "All games solved.");
    } 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;

static long long clampLL(long long x, long long lo, long long hi) {
    if (x < lo) return lo;
    if (x > hi) return hi;
    return x;
}

static long long powLLBounded(long long base, int exp, long long limit) {
    __int128 v = 1;
    for (int i = 0; i < exp; i++) {
        v *= (__int128)base;
        if (v > (__int128)limit) return limit + 1;
    }
    return (long long)v;
}

static long long genStructuredX(long long c) {
    long long sq = (long long)sqrt((long double)c);
    sq = max(2LL, min(sq, c));

    int kind = rnd.next(1, 4);
    if (kind == 1) {
        long long a = rnd.next(2LL, sq);
        long long b = rnd.next(2LL, sq);
        __int128 prod = (__int128)a * (__int128)b;
        long long x;
        if (prod <= (__int128)c) {
            x = (long long)prod;
        } else {
            long long m = a;
            if (m <= 0) m = 2;
            x = (c / m) * m;
            if (x <= 0) x = 1;
            if (x > c) x = c;
        }
        return clampLL(x, 1, c);
    } else if (kind == 2) {
        for (int tries = 0; tries < 40; tries++) {
            long long base = rnd.next(2LL, min(1000000LL, c));
            int exp = rnd.next(2, 6);
            long long x = powLLBounded(base, exp, c);
            if (1 <= x && x <= c) return x;
        }
        long long base = rnd.next(2LL, min(50000LL, c));
        long long x = base * base;
        if (x < 1) x = 1;
        if (x > c) x = c;
        return x;
    } else if (kind == 3) {
        int bits = rnd.next(1, 31);
        long long x = (bits == 31) ? (long long)INT_MAX : ((1LL << bits) - 1);
        if (x > c) x = c;
        if (x < 1) x = 1;
        return x;
    } else {
        long long m = rnd.next(2LL, min(1000000LL, c));
        long long x = (c / m) * m;
        if (x == 0) x = m;
        x = clampLL(x, 1, c);
        if (rnd.next(0, 1) && x - m >= 1) x -= m;
        if (rnd.next(0, 1) && x + m <= c) x += m;
        return clampLL(x, 1, c);
    }
}

static long long genRandomX(long long c) {
    int bucket = rnd.next(1, 100);

    if (bucket <= 10) {
        long long hi = min(c, 1000000LL);
        return rnd.next(1LL, hi);
    } else if (bucket <= 30) {
        long long lo = max(1LL, c / 3);
        long long hi = min(c, (2LL * c) / 3);
        if (lo > hi) swap(lo, hi);
        return rnd.next(lo, hi);
    } else if (bucket <= 80) {
        long long lo = max(1LL, c - 10000000LL);
        return rnd.next(lo, c);
    } else {
        return genStructuredX(c);
    }
}

static vector<long long> craftedNon(int seed, long long c) {
    vector<long long> v;
    auto push = [&](long long x) {
        x = clampLL(x, 1, c);
        v.push_back(x);
    };

    if (seed == 1) {
        push(1);
        push(2);
        push(3);
        push(4);
        push(5);
        push(6);
        push(7);
        push(8);
        push(9);
        push(10);
        push(42);
        push(1000000);
        push(999999937LL);
        push(1073741824LL);
        push(1162261467LL);
        push(c - 2);
        push(c - 1);
        push(c);
    } else if (seed == 2) {
        push(c);
        push(c - 1);
        push(c - 2);
        push(c - 3);
        push(c / 2);
        push(c / 2 + 1);
        push(max(1LL, c - 1000));
        push(max(1LL, c - 999));
        push(1073741824LL);
        push(536870912LL);
        push(268435456LL);
        push(1162261467LL);
        push(3486784401LL); 
        push(1999999943LL);
        push(1999999999LL);
    } else {
        push(42);
        push(1);
        push(2);
        push(3);
        push(100);
        push(999);
        push(1024);
        push(65536);
        push(1000000);
        push(123456789);
        push(987654321);
        push(999999996);
        push(1000000000);
        push(1000000001);
        push(1073741824LL);
        push(1162261467LL);
        push(1999999943LL);
        push(c - 1);
        push(c);
    }

    for (auto &x : v) x = clampLL(x, 1, c);
    return v;
}

static vector<pair<long long,long long>> craftedAdp(int seed, long long c) {
    vector<pair<long long,long long>> v;
    auto push = [&](long long l, long long r) {
        l = clampLL(l, 1, c);
        r = clampLL(r, 1, c);
        if (l > r) swap(l, r);
        v.push_back({l, r});
    };

    if (seed == 1) {
        push(1, 1);
        push(2, 2);
        push(1, 2);
        push(1, 3);
        push(c, c);
        push(c - 1, c);
        push(1, c);
        push(max(1LL, c - 1000), c);
        push(1, min(c, 1000000LL));
        push(42, 42);
        push(1000000, 1000000);
        push(1073741824LL, 1073741824LL);
    } else if (seed == 2) {
        push(1, c);
        push(1, c);
        push(max(1LL, c - 10000000LL), c);
        push(max(1LL, c - 10000000LL), c);
        push(1, min(c, 1000000LL));
        push(c / 2, min(c, c / 2 + 1000));
        push(max(1LL, c / 2 - 1000), c / 2);
        push(c - 1, c);
        push(c, c);
    } else {
        push(1, c);
        push(1, c);
        push(1, min(c, 1000000LL));
        push(max(1LL, c - 10000000LL), c);
        push(42, 43);
        push(999999937LL, 999999937LL);
        push(1073741824LL, 1073741824LL);
        push(1162261467LL, 1162261467LL);
        push(c - 2, c);
    }

    return v;
}

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

    string mode = opt<string>("mode", "non");
    int tOpt = opt<int>("t", 10000);
    int k = opt<int>("k", 3);
    long long c = opt<long long>("c", 2000000000LL);

    ensuref(mode == "non" || mode == "adp", "Unknown --mode (expected non/adp).");
    ensuref(1 <= tOpt && tOpt <= 10000, "t out of range.");
    ensuref(1 <= k && k <= 10, "k out of range.");
    ensuref(2 <= c, "c too small.");

    int seed = 0;
    if (argc >= 2) seed = atoi(argv[1]);
    int t = tOpt;

    cout << t << " " << k << " " << c << "\n";

    if (mode == "non") {
        vector<long long> xs;
        if (seed >= 1 && seed <= 3) {
            xs = craftedNon(seed, c);
        }

        for (int i = 0; i < t; i++) {
            long long x;
            if (seed >= 1 && seed <= 3) {
                x = xs[i % (int)xs.size()];
            } else {
                if (i == 0) x = 1;
                else if (i == 1) x = c;
                else if (i == 2) x = max(1LL, c - 1);
                else if (i == 3) x = clampLL(1073741824LL, 1, c);
                else if (i == 4) x = clampLL(1162261467LL, 1, c);
                else {
                    x = genRandomX(c);
                    if (rnd.next(1, 100) <= 75) {
                        long long lo = max(1LL, c - 20000000LL);
                        x = rnd.next(lo, c);
                    }
                }
            }
            x = clampLL(x, 1, c);
            cout << x << "\n";
        }
    } else {
        vector<pair<long long,long long>> segs;
        if (seed >= 1 && seed <= 3) {
            segs = craftedAdp(seed, c);
        }

        for (int i = 0; i < t; i++) {
            long long L, R;
            if (seed >= 1 && seed <= 3) {
                auto pr = segs[i % (int)segs.size()];
                L = pr.first;
                R = pr.second;
            } else {
                int bucket = rnd.next(1, 100);
                if (i < 2 || bucket <= 70) {
                    L = 1;
                    R = c;
                } else if (bucket <= 85) {
                    L = max(1LL, c - 20000000LL);
                    R = c;
                } else if (bucket <= 95) {
                    L = 1;
                    R = min(c, 1000000LL);
                } else {
                    long long center = genRandomX(c);
                    long long w = rnd.next(0LL, 2000LL);
                    L = clampLL(center - w, 1, c);
                    R = clampLL(center + w, 1, c);
                    if (L > R) swap(L, R);
                }
            }
            L = clampLL(L, 1, c);
            R = clampLL(R, 1, c);
            if (L > R) swap(L, R);
            cout << L << " " << R << "\n";
        }
    }

    return 0;
}