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

### Problem Statement

**This is an interactive task.**

Snuke has a favorite positive integer, $N$. You can ask him the following type of question at most $64$ times: "Is $n$ your favorite integer?" Identify $N$.

Snuke is twisted, and when asked "Is $n$ your favorite integer?", he answers "Yes" if one of the two conditions below is satisfied, and answers "No" otherwise:

* Both $n \leq N$ and $str(n) \leq str(N)$ hold.
* Both $n > N$ and $str(n) > str(N)$ hold.

Here, $str(x)$ is the decimal representation of $x$ (without leading zeros) as a string. For example, $str(123) =$ `123` and $str(2000)$ = `2000`.
Strings are compared lexicographically. For example, `11111` $<$ `123` and `123456789` $<$ `9`.

### Constraints

* $1 \leq N \leq 10^{9}$

### Input and Output

Write your question to Standard Output in the following format:

```
? $n$
```

Here, $n$ must be an integer between $1$ and $10^{18}$ (inclusive).

Then, the response to the question shall be given from Standard Input in the following format:

```
$ans$
```

Here, $ans$ is either `Y` or `N`. `Y` represents "Yes"; `N` represents "No".

Finally, write your answer in the following format:

```
! $n$
```

Here, $n=N$ must hold.

---

### Judging

* **After each output, you must flush Standard Output.** Otherwise you may get `TLE`.
* After you print the answer, the program must be terminated immediately. Otherwise, the behavior of the judge is undefined.
* When your output is invalid or incorrect, the behavior of the judge is undefined (it does not necessarily give `WA`).

### Sample

Below is a sample communication for the case $N=123$:

| Input | Output |
| --- | --- |
|  | `? 1` |
| `Y` |  |
|  | `? 32` |
| `N` |  |
|  | `? 1010` |
| `N` |  |
|  | `? 999` |
| `Y` |  |
|  | `! 123` |

* Since $1 \leq 123$ and $str(1) \leq str(123)$, the first response is "Yes".
* Since $32 \leq 123$ but $str(32) > str(123)$, the second response is "No".
* Since $1010 > 123$ but $str(1010) \leq str(123)$, the third response is "No".
* Since $999 \geq 123$ and $str(999) > str(123)$, the fourth response is "Yes".
* The program successfully identifies $N=123$ in four questions, and thus passes the case.

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


static long long queries = 0;
static const long long query_limit = 64; 
static long long N_hidden;


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 is_digit_str(const string& s) {
    if (s.empty()) return false;
    for (char c : s) {
        if (!isdigit((unsigned char)c)) return false;
    }
    return true;
}

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

    
    
    N_hidden = inf.readLong();
    
    
    log_metrics();

    string token;
    while (cin >> token) {
        if (token == "!") {
            
            string ans_str;
            if (!(cin >> ans_str)) {
                finish(_pe, "Expected answer number after '!'");
            }
            long long ans_val;
            try {
                if (!is_digit_str(ans_str)) finish(_pe, "Answer token is not a valid number: " + ans_str);
                ans_val = stoll(ans_str);
            } catch (...) {
                finish(_pe, "Answer number parse error: " + ans_str);
            }

            if (ans_val == N_hidden) {
                finish(_ok, "Correct answer");
            } else {
                finish(_wa, "Wrong Answer: expected " + to_string(N_hidden) + ", got " + to_string(ans_val));
            }
        } else {
            
            string n_str;
            if (token == "?") {
                if (!(cin >> n_str)) {
                    finish(_pe, "Expected number after '?'");
                }
            } else {
                
                n_str = token;
            }

            long long n_val;
            try {
                if (!is_digit_str(n_str)) finish(_pe, "Query token is not a valid number: " + n_str);
                n_val = stoll(n_str);
            } catch (...) {
                finish(_pe, "Query number parse error or out of range: " + n_str);
            }

            
            if (n_val < 1 || n_val > 1000000000000000000LL) {
                finish(_pe, "Query parameter out of range [1, 10^18]: " + n_str);
            }

            queries++;
            
            if (queries % 10 == 0) log_metrics();

            
            if (queries > 2000) {
                finish(_pe, "Query limit hard cap exceeded (> 2000)");
            }

            
            
            
            bool num_le = (n_val <= N_hidden);
            
            
            string s_n = to_string(n_val);
            string s_N = to_string(N_hidden);
            bool lex_le = (s_n <= s_N); 

            
            bool res = (num_le == lex_le);
            cout << (res ? "Y" : "N") << endl;
        }
    }

    finish(_pe, "Unexpected EOF (did not receive answer)");
    return 0;
}


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


static long long queries = 0;
static long long query_limit = 64; 


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


string to_str(long long x) {
    return to_string(x);
}



bool get_response(long long n, long long N) {
    bool val_le = (n <= N);
    bool str_le = (to_str(n) <= to_str(N));
    
    
    
    return (val_le == str_le);
}

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

    
    
    long long input1 = inf.readLong();
    long long input2 = -1;
    
    
    if (!inf.seekEof()) {
        input2 = inf.readLong();
    }
    
    
    vector<long long> pool;
    long long L = 1, R = 1000000000;

    if (input2 == -1) {
        
        pool.push_back(input1);
    } else {
        
        L = input1;
        R = input2;
        
        
        if (R - L + 1 <= 50000) {
            for (long long i = L; i <= R; ++i) pool.push_back(i);
        } else {
            
            
            
            set<long long> candidates;
            candidates.insert(L);
            candidates.insert(R);
            
            
            for (long long p = 1; p <= R; ) {
                for (int d = 1; d <= 9; ++d) {
                    long long base = p * d;
                    for (long long offset : {-1, 0, 1}) {
                        long long val = base + offset;
                        if (val >= L && val <= R) candidates.insert(val);
                    }
                    if (d == 9 && p > R / 10) break; 
                }
                if (p > R / 10) break; 
                p *= 10;
            }
            
            
            int attempts = 0;
            while (candidates.size() < 40000 && attempts < 100000) {
                long long x = rnd.next(L, R);
                candidates.insert(x);
                attempts++;
            }
            
            for (long long x : candidates) pool.push_back(x);
        }
    }
    
    
    shuffle(pool.begin(), pool.end());

    
    while (true) {
        
        if (queries % 10 == 0) log_metrics();
        
        string type;
        if (!(cin >> type)) {
            finish(_pe, "Unexpected EOF");
        }
        
        if (type == "!") {
            long long ans;
            if (!(cin >> ans)) finish(_pe, "Expected number after !");
            
            
            
            long long counter_example = -1;
            bool found_ans = false;
            
            for (long long cand : pool) {
                if (cand == ans) found_ans = true;
                else counter_example = cand;
            }
            
            if (counter_example != -1) {
                
                finish(_wa, "Wrong Answer (counter-example exists)"); 
            } else if (found_ans) {
                
                finish(_ok, "Correct");
            } else {
                
                finish(_pe, "Inconsistent interaction (empty feasible set)");
            }
            
        } else if (type == "?") {
            long long n;
            if (!(cin >> n)) finish(_pe, "Expected number after ?");
            
            if (n < 1 || n > 1000000000000000000LL) {
                finish(_pe, "Query out of range [1, 10^18]");
            }
            
            queries++;
            
            if (queries > 200) {
                finish(_pe, "Too many queries (hard cap exceeded)");
            }
            
            
            int yes_votes = 0;
            int no_votes = 0;
            for (long long cand : pool) {
                if (get_response(n, cand)) yes_votes++;
                else no_votes++;
            }
            
            string reply;
            bool reply_val;
            
            
            if (yes_votes >= no_votes) {
                reply = "Y";
                reply_val = true;
            } else {
                reply = "N";
                reply_val = false;
            }
            
            cout << reply << endl; 
            
            
            auto it = std::remove_if(pool.begin(), pool.end(), [&](long long cand){
                return get_response(n, cand) != reply_val;
            });
            pool.erase(it, pool.end());
            
            if (pool.empty()) {
                
                finish(_wa, "Inconsistent queries (eliminated all candidates)");
            }
        } else {
            finish(_pe, "Invalid query format");
        }
    }
    
    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");

    
    
    if (mode == "adp") {
        cout << "1 1000000000" << endl;
        return 0;
    }

    
    long long n = 1;
    long long seed_val = -1;
    
    
    try {
        seed_val = stoll(string(argv[1]));
    } catch (...) {
        seed_val = -1;
    }

    if (seed_val == 1) n = 1;
    else if (seed_val == 2) n = 1000000000;
    else if (seed_val == 3) n = 999999999;
    else if (seed_val == 4) n = 10;
    else if (seed_val == 5) n = 9;
    else {
        
        int type = rnd.next(5);
        if (type == 0) {
            
            int k = rnd.next(0, 9);
            long long p = 1;
            for(int i=0; i<k; ++i) p *= 10;
            n = p;
        } else if (type == 1) {
            
            int k = rnd.next(1, 9);
            long long p = 1;
            for(int i=0; i<k; ++i) p *= 10;
            n = p - 1;
        } else if (type == 2) {
            
            
            int k = rnd.next(1, 8);
            long long p = 1;
            for(int i=0; i<k; ++i) p *= 10;
            n = p + 1;
        } else if (type == 3) {
            
            long long d = rnd.next(1, 9);
            int k = rnd.next(0, 8);
            long long p = 1;
            for(int i=0; i<k; ++i) p *= 10;
            n = d * p;
        } else {
            
            n = rnd.next(1, 1000000000);
        }
    }

    
    if (n < 1) n = 1;
    if (n > 1000000000) n = 1000000000;

    cout << n << endl;
    return 0;
}