Problem: cf1290_d
Difficulty: medium
Categories: graph
Time limit: 1000 ms, memory limit: 256 MB

This is the hard version of the problem. You can find the easy version in the Div. 2 contest. Both versions only differ in the number of times you can ask your friend to taste coffee.

This is an interactive problem.

You're considering moving to another city, where one of your friends already lives. There are $n$ cafés in this city, where $n$ is a power of two. The $i$-th café produces a single variety of coffee $a_i$.

As you're a coffee-lover, before deciding to move or not, you want to know the number $d$ of distinct varieties of coffees produced in this city.

You don't know the values $a_1, \ldots, a_n$. Fortunately, your friend has a memory of size $k$, where $k$ is a power of two.

Once per day, you can ask him to taste a cup of coffee produced by the café $c$, and he will tell you if he tasted a similar coffee during the last $k$ days.

You can also ask him to take a medication that will reset his memory. He will forget all previous cups of coffee tasted. You can reset his memory at most $30\ 000$ times.

More formally, the memory of your friend is a queue $S$. Doing a query on café $c$ will:

* Tell you if $a_c$ is in $S$;
* Add $a_c$ at the back of $S$;
* If $|S| > k$, pop the front element of $S$.

Doing a reset request will pop all elements out of $S$.

Your friend can taste at most $\dfrac{3n^2}{2k}$ cups of coffee in total. Find the diversity $d$ (number of distinct values in the array $a$).

Note that asking your friend to reset his memory does not count towards the number of times you ask your friend to taste a cup of coffee.

In some test cases the behavior of the interactor is adaptive. It means that the array $a$ may be not fixed before the start of the interaction and may depend on your queries. It is guaranteed that at any moment of the interaction, there is at least one array $a$ consistent with all the answers given so far.

Input

The first line contains two integers $n$ and $k$ ($1 \le k \le n \le 1024$, $k$ and $n$ are powers of two).

It is guaranteed that $\dfrac{3n^2}{2k} \le 15\ 000$.

Interaction

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

* To ask your friend to taste a cup of coffee produced by the café $c$, in a separate line output

  ? $c$

  Where $c$ must satisfy $1 \le c \le n$. Don't forget to flush, to get the answer.

  In response, you will receive a single letter Y (yes) or N (no), telling you if variety $a_c$ is one of the last $k$ varieties of coffee in his memory.
* To reset the memory of your friend, in a separate line output the single letter R in upper case. You can do this operation at most $30\ 000$ times.
* When you determine the number $d$ of different coffee varieties, output

  ! $d$

In case your query is invalid, you asked more than $\frac{3n^2}{2k}$ queries of type ? or you asked more than $30\ 000$ queries of type R, the program will print the letter E and will finish interaction. You will receive a Wrong Answer verdict. Make sure to exit immediately to avoid getting other verdicts.

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.

Examples

Input

```
4 2
N
N
Y
N
N
N
N
```

Output

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

Input

```
8 8
N
N
N
N
Y
Y
```

Output

```
? 2
? 6
? 4
? 5
? 2
? 5
! 6
```

Note

In the first example, the array is $a = [1, 4, 1, 3]$. The city produces $3$ different varieties of coffee ($1$, $3$ and $4$).

The successive varieties of coffee tasted by your friend are $1, 4, \textbf{1}, 3, 3, 1, 4$ (bold answers correspond to Y answers). Note that between the two ? 4 asks, there is a reset memory request R, so the answer to the second ? 4 ask is N. Had there been no reset memory request, the answer to the second ? 4 ask is Y.

In the second example, the array is $a = [1, 2, 3, 4, 5, 6, 6, 6]$. The city produces $6$ different varieties of coffee.

The successive varieties of coffee tasted by your friend are $2, 6, 4, 5, \textbf{2}, \textbf{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 << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}

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

static bool parseLongLong(const string& s, long long& out) {
    if (s.empty()) return false;
    int i = 0;
    bool neg = false;
    if (s[i] == '-') {
        neg = true;
        i++;
        if (i == (int)s.size()) return false;
    }
    long long val = 0;
    for (; i < (int)s.size(); i++) {
        if (s[i] < '0' || s[i] > '9') return false;
        int d = s[i] - '0';
        if (val > (LLONG_MAX - d) / 10) return false;
        val = val * 10 + d;
    }
    out = neg ? -val : val;
    return true;
}

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

    int n = 0, k = 0;
    try {
        n = inf.readInt(1, 1024, "n");
        k = inf.readInt(1, 1024, "k");
    } catch (...) {
        query_limit = 0;
        log_metrics();
        finish(_fail, "Invalid hidden input: failed to read n and k.");
    }

    if ((n & (n - 1)) != 0 || (k & (k - 1)) != 0 || k > n) {
        query_limit = 0;
        log_metrics();
        finish(_fail, "Invalid hidden input: n and k must be powers of two with k <= n.");
    }

    
    vector<long long> tail;
    while (!inf.seekEof()) {
        try {
            tail.push_back(inf.readLong());
        } catch (...) {
            break;
        }
    }

    vector<long long> a(n);
    if ((int)tail.size() >= n) {
        for (int i = 0; i < n; i++) a[i] = tail[i];
    } else if ((int)tail.size() == 1) {
        
        long long d = tail[0];
        if (d < 1) d = 1;
        if (d > n) d = n;
        for (int i = 0; i < n; i++) {
            if (i < d) a[i] = (long long)i + 1;
            else a[i] = 1;
        }
    } else if ((int)tail.size() == 0) {
        
        for (int i = 0; i < n; i++) a[i] = (long long)i + 1;
    } else {
        
        for (int i = 0; i < (int)tail.size() && i < n; i++) a[i] = tail[i];
        long long fill = (tail.empty() ? 1LL : tail[0]);
        for (int i = (int)tail.size(); i < n; i++) a[i] = fill;
    }

    vector<long long> tmp = a;
    sort(tmp.begin(), tmp.end());
    tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());
    long long distinct_count = (long long)tmp.size();

    query_limit = (3LL * (long long)n * (long long)n) / (2LL * (long long)k);
    long long hard_cap = max(200000LL, 10LL * query_limit);

    
    log_metrics();

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

    deque<long long> mem;
    unordered_map<long long, int> freq;
    freq.reserve((size_t)k * 2 + 8);

    long long resets = 0;

    while (true) {
        string cmd;
        if (!(cin >> cmd)) {
            finish(_pe, "Unexpected EOF from contestant.");
        }

        bool isQuery = false, isAnswer = false, isReset = false;
        string inlineNum;

        if (cmd == "?") {
            isQuery = true;
        } else if (cmd == "!") {
            isAnswer = true;
        } else if (cmd == "R") {
            isReset = true;
        } else if (!cmd.empty() && cmd[0] == '?' && cmd.size() > 1) {
            isQuery = true;
            inlineNum = cmd.substr(1);
        } else if (!cmd.empty() && cmd[0] == '!' && cmd.size() > 1) {
            isAnswer = true;
            inlineNum = cmd.substr(1);
        } else {
            finish(_pe, "Malformed command token.");
        }

        if (isReset) {
            resets++;
            if (resets > 30000) {
                cout << "E" << endl;
                cout.flush();
                finish(_wa, "Reset limit exceeded.");
            }
            mem.clear();
            freq.clear();
            continue;
        }

        if (isQuery) {
            long long c = 0;
            if (!inlineNum.empty()) {
                if (!parseLongLong(inlineNum, c)) {
                    finish(_pe, "Malformed cafe index in inline query.");
                }
            } else {
                string s;
                if (!(cin >> s)) finish(_pe, "Unexpected EOF after '?'");
                if (!parseLongLong(s, c)) finish(_pe, "Malformed cafe index.");
            }

            if (c < 1 || c > n) {
                cout << "E" << endl;
                cout.flush();
                finish(_wa, "Cafe index out of range.");
            }

            queries++;
            if (queries > hard_cap) {
                finish(_pe, "Hard cap exceeded (possible infinite loop).");
            }

            long long val = a[(int)c - 1];
            bool seen = false;
            auto it = freq.find(val);
            if (it != freq.end() && it->second > 0) seen = true;

            cout << (seen ? 'Y' : 'N') << endl;
            cout.flush();

            mem.push_back(val);
            freq[val]++;

            if ((int)mem.size() > k) {
                long long front = mem.front();
                mem.pop_front();
                auto it2 = freq.find(front);
                if (it2 != freq.end()) {
                    it2->second--;
                    if (it2->second <= 0) freq.erase(it2);
                }
            }
            continue;
        }

        if (isAnswer) {
            long long ans = 0;
            if (!inlineNum.empty()) {
                if (!parseLongLong(inlineNum, ans)) {
                    finish(_pe, "Malformed answer in inline '!'.");
                }
            } else {
                string s;
                if (!(cin >> s)) finish(_pe, "Unexpected EOF after '!'");
                if (!parseLongLong(s, ans)) finish(_pe, "Malformed answer.");
            }

            if (ans == distinct_count) {
                finish(_ok, "Correct.");
            } else {
                finish(_wa, "Wrong answer.");
            }
        }
    }
}


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

struct MemoryQueue {
    int k = 0;
    deque<long long> q;
    unordered_map<long long, int> cnt;

    explicit MemoryQueue(int kk = 0) : k(kk) {
        cnt.reserve(2048);
        cnt.max_load_factor(0.7f);
    }

    bool contains(long long x) const {
        return cnt.find(x) != cnt.end();
    }

    void push(long long x) {
        q.push_back(x);
        cnt[x]++;
        if ((int)q.size() > k) {
            long long y = q.front();
            q.pop_front();
            auto it = cnt.find(y);
            if (it != cnt.end()) {
                it->second--;
                if (it->second == 0) cnt.erase(it);
            }
        }
    }

    void reset() {
        q.clear();
        cnt.clear();
    }
};

static void send_error_and_finish(const string& msg) {
    cout << "E" << endl;
    cout.flush();
    finish(_pe, msg);
}

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

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

    int n = inf.readInt(1, 1024, "n");
    int k = inf.readInt(1, n, "k");

    vector<long long> rest;
    while (!inf.seekEof()) rest.push_back(inf.readLong());

    bool adaptive = false;
    int dTarget = 0;
    vector<long long> a;

    if ((int)rest.size() == 1) {
        adaptive = true;
        long long d = rest[0];
        if (d < 1 || d > n) finish(_fail, "Invalid d in input");
        dTarget = (int)d;
    } else {
        adaptive = false;
        if ((int)rest.size() != n) finish(_fail, "Invalid fixed-array input size");
        a = rest;
        vector<long long> tmp = a;
        sort(tmp.begin(), tmp.end());
        tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());
        dTarget = (int)tmp.size();
    }

    query_limit = (3LL * n * n) / (2LL * k);
    long long hard_cap = max(200000LL, 10LL * max(1LL, query_limit));
    log_metrics(); 

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

    MemoryQueue mem(k);

    long long resets = 0;

    vector<int> labelOfCafe;
    int assignedCount = 0;
    int usedLabels = 0;
    if (adaptive) labelOfCafe.assign(n + 1, 0);

    auto handle_adaptive_query = [&](int c) {
        long long val = 0;
        char reply = 'N';

        if (labelOfCafe[c] != 0) {
            val = labelOfCafe[c];
            reply = mem.contains(val) ? 'Y' : 'N';
        } else {
            int remainingAfter = n - (assignedCount + 1);

            bool canKeepUsed = ((long long)usedLabels + remainingAfter >= (long long)dTarget);
            bool canIncUsed = (usedLabels < dTarget) &&
                              ((long long)(usedLabels + 1) + remainingAfter >= (long long)dTarget);

            vector<char> inS(usedLabels + 1, false);
            for (const auto& kv : mem.cnt) {
                long long x = kv.first;
                if (1 <= x && x <= usedLabels) inS[(int)x] = true;
            }

            int cntIn = 0, cntOut = 0;
            int smallestIn = 0, smallestOut = 0;
            for (int i = 1; i <= usedLabels; i++) {
                if (inS[i]) {
                    cntIn++;
                    if (!smallestIn) smallestIn = i;
                } else {
                    cntOut++;
                    if (!smallestOut) smallestOut = i;
                }
            }

            bool Ypossible = canKeepUsed && (cntIn > 0);
            bool NexistPossible = canKeepUsed && (cntOut > 0);
            bool NnewPossible = canIncUsed;
            bool Npossible = NexistPossible || NnewPossible;

            if (!Ypossible && !Npossible) finish(_fail, "No feasible adaptive continuation");

            char chosenAns = 'N';
            if (Ypossible && Npossible) {
                long long choicesY = cntIn;
                long long choicesN = (NexistPossible ? cntOut : 0) + (NnewPossible ? 1 : 0);
                if (choicesN > choicesY) chosenAns = 'N';
                else if (choicesN < choicesY) chosenAns = 'Y';
                else chosenAns = 'N';
            } else if (Npossible) {
                chosenAns = 'N';
            } else {
                chosenAns = 'Y';
            }

            int chosenLabel = 0;
            if (chosenAns == 'Y') {
                chosenLabel = smallestIn;
                if (!chosenLabel) finish(_fail, "Y chosen but no in-S label");
            } else {
                if (!canKeepUsed) {
                    if (!canIncUsed) finish(_fail, "Must increase used labels but cannot");
                    usedLabels++;
                    chosenLabel = usedLabels;
                } else if (NexistPossible) {
                    chosenLabel = smallestOut;
                    if (!chosenLabel) finish(_fail, "N-exist chosen but no out-of-S label");
                } else {
                    if (!NnewPossible) finish(_fail, "N chosen but neither existing nor new feasible");
                    usedLabels++;
                    chosenLabel = usedLabels;
                }
            }

            if (chosenLabel < 1 || chosenLabel > dTarget) finish(_fail, "Chosen label out of range");
            labelOfCafe[c] = chosenLabel;
            assignedCount++;

            val = chosenLabel;
            bool inMemNow = mem.contains(val);
            reply = inMemNow ? 'Y' : 'N';

            if (reply != chosenAns) finish(_fail, "Internal adaptive inconsistency");
        }

        cout << reply << endl;
        cout.flush();
        mem.push(val);
    };

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

        if (op == "?") {
            long long cLL;
            if (!(cin >> cLL)) send_error_and_finish("Missing cafe index after '?'");
            if (cLL < 1 || cLL > n) send_error_and_finish("Cafe index out of range");
            int c = (int)cLL;

            queries++;
            if (queries > hard_cap) send_error_and_finish("Too many queries (hard cap exceeded)");

            if (!adaptive) {
                long long val = a[c - 1];
                char reply = mem.contains(val) ? 'Y' : 'N';
                cout << reply << endl;
                cout.flush();
                mem.push(val);
            } else {
                handle_adaptive_query(c);
            }
        } else if (op == "R") {
            resets++;
            if (resets > 30000) send_error_and_finish("Too many resets");
            mem.reset();
        } else if (op == "!") {
            long long ans;
            if (!(cin >> ans)) send_error_and_finish("Missing answer after '!'");
            if (ans == (long long)dTarget) finish(_ok, "Correct");
            finish(_wa, "Wrong diversity");
        } else {
            send_error_and_finish("Unknown operation");
        }
    }
}


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

static bool isPow2(int x) { return x > 0 && (x & (x - 1)) == 0; }

static int highestPow2LE(int x) {
    int p = 1;
    while ((p << 1) > 0 && (p << 1) <= x) p <<= 1;
    return p;
}

template <class T>
static void shuffleVec(vector<T>& v) {
    for (int i = (int)v.size() - 1; i >= 1; --i) {
        int j = rnd.next(0, i);
        swap(v[i], v[j]);
    }
}

static void adjustNK(int& n, int& k) {
    if (!isPow2(n)) n = max(1, highestPow2LE(n));
    if (!isPow2(k)) k = max(1, highestPow2LE(k));
    k = min(k, n);

    long long nn = n;
    while (k < n && (3LL * nn * nn) / (2LL * (long long)k) > 15000LL) k <<= 1;
    if (k > n) k = n;
    if (!isPow2(k)) k = highestPow2LE(k);
    if (k < 1) k = 1;
}

static vector<long long> genAllDistinct(int n) {
    vector<long long> vals(n);
    for (int i = 0; i < n; i++) vals[i] = (long long)i + 1;
    shuffleVec(vals);
    return vals;
}

static vector<long long> genOneDuplicateFar(int n) {
    vector<long long> a = genAllDistinct(n);
    a[n - 1] = a[0];
    return a;
}

static vector<long long> genFewDuplicatesFar(int n, int t) {
    vector<long long> a = genAllDistinct(n);
    t = max(1, min(t, min(n / 8, n - 1)));
    int L = n / 4;
    int R = n / 4;
    if (L <= 0 || R <= 0) {
        a[n - 1] = a[0];
        return a;
    }

    vector<int> src(L), dst(R);
    for (int i = 0; i < L; i++) src[i] = i;
    for (int i = 0; i < R; i++) dst[i] = (3 * n) / 4 + i;
    shuffleVec(src);
    shuffleVec(dst);

    t = min(t, min((int)src.size(), (int)dst.size()));
    for (int i = 0; i < t; i++) a[dst[i]] = a[src[i]];
    return a;
}

static vector<long long> genPairsTwoHalves(int n) {
    int m = n / 2;
    vector<long long> p(m), q(m);
    for (int i = 0; i < m; i++) p[i] = (long long)i + 1;
    q = p;
    shuffleVec(p);
    shuffleVec(q);
    vector<long long> a(n);
    for (int i = 0; i < m; i++) a[i] = p[i];
    for (int i = 0; i < m; i++) a[m + i] = q[i];
    return a;
}

static vector<long long> genPeriodicBeyondK(int n, int k) {
    int step = k + 1;
    vector<long long> a(n);
    for (int i = 0; i < n; i++) a[i] = (long long)((i % step) + 1);
    return a;
}

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

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

    string mode = opt<string>("mode", "non");
    int n = opt<int>("n", 1024);
    int k = opt<int>("k", 128);
    int dOpt = opt<int>("d", -1);

    adjustNK(n, k);

    if (mode != "adp" && mode != "non") mode = "non";

    if (mode == "adp") {
        int d;
        if (dOpt != -1) {
            d = dOpt;
        } else if (seed == 1) {
            n = 1;
            k = 1;
            d = 1;
        } else if (seed == 2) {
            n = 1024;
            k = 128;
            adjustNK(n, k);
            d = n;
        } else if (seed == 3) {
            n = 1024;
            k = 128;
            adjustNK(n, k);
            d = n - 1;
        } else {
            int kind = (int)(seed % 5);
            if (kind == 0) {
                d = n - 1;
            } else if (kind == 1) {
                int t = rnd.next(2, min(16, n - 1));
                d = n - t;
            } else if (kind == 2) {
                d = n / 2;
            } else if (kind == 3) {
                d = min(n, k + 1);
            } else {
                int lo = max(1, n / 8);
                d = rnd.next(lo, n);
            }
        }
        d = max(1, min(d, n));
        cout << n << " " << k << " " << d << "\n";
        return 0;
    }

    vector<long long> a;
    if (seed == 1) {
        n = 1;
        k = 1;
        a = vector<long long>{1};
    } else if (seed == 2) {
        n = 1024;
        k = 128;
        adjustNK(n, k);
        a = genAllDistinct(n);
    } else if (seed == 3) {
        n = 1024;
        k = 128;
        adjustNK(n, k);
        a = genOneDuplicateFar(n);
    } else {
        n = min(n, 1024);
        n = max(n, 1);
        if (!isPow2(n)) n = highestPow2LE(n);
        k = min(k, n);
        adjustNK(n, k);

        int kind = rnd.next(1, 100);
        if (kind <= 60) {
            int t = rnd.next(1, min(16, n - 1));
            a = genFewDuplicatesFar(n, t);
        } else if (kind <= 80) {
            a = genPairsTwoHalves(n);
        } else if (kind <= 90) {
            a = genPeriodicBeyondK(n, k);
        } else {
            int t = rnd.next(1, min(8, n - 1));
            a = genFewDuplicatesFar(n, t);
            if (n >= 2) {
                int pos = rnd.next(n / 2, n - 1);
                a[pos] = a[0];
            }
        }
    }

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