Problem: arc070_d
Difficulty: medium
Categories: greedy, data structures, math
Time limit: 2000 ms, memory limit: 256 MB

### Problem Statement

**This is an interactive task.**

AtCoDeer the deer came across $N$ people. For convenience, the people are numbered $0$ through $N-1$.
Among them, $A$ are *honest* and the remaining $B(=N-A)$ are *unkind*.
All of these $N$ people know who are honest and who are unkind, but AtCoDeer only knows that there are $A$ honest and $B$ unkind people.
He is trying to identify all of the honest people by asking questions to these $N$ people.
For one question, AtCoDeer selects $a$ and $b$ $(0≤a,b≤N-1)$, and asks person $a$ the following question: "Is person $b$ honest?"

An honest person will always answer correctly by "Yes" or "No".
An unkind person, however, will answer by selecting "Yes" or "No" **arbitrarily**.
That is, the algorithm used by an unkind person may not be simple one such as always lying or giving random fifty-fifty answers.

AtCoDeer can ask at most $2N$ questions. He will ask questions one by one, and the responses to the previous questions can be used when deciding the next question to ask.

Identify all of the honest people.
If it is impossible (more formally, if, for any strategy of asking $2N$ questions, there exists a strategy for unkind people to answer the questions so that there are two or more possible sets of the honest people), report that fact.

### Constraints

* $1≤A,B≤2000$

### Input and Output

First, $A$ and $B$ are given from Standard Input in the following format:

```
$A$ $B$
```

If identifying the honest people is impossible, the program must immediately print the following output and terminate itself:

```
Impossible
```

Otherwise, the program shall ask questions.
Each question must be written to Standard Output in the following format:

```
? $a$ $b$
```

Here, $a$ and $b$ must be integers between $0$ and $N-1$ (inclusive).
The response to the question will be given from Standard Input in the following format:

```
$ans$
```

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

Finally, the answer must be written to Standard Output in the following format:

```
! $s_0s_1...s_{N-1}$
```

Here, $s_i$ must be `1` if person $i$ is honest, and `0` if person $i$ is unkind.

### Judgement

* **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`).

### Samples

In the following sample, $A = 2$, $B = 1$, and the answer is `101`.

| Input | Output |
| --- | --- |
| $2$ $1$ |  |
|  | $?$ $0$ $1$ |
| $N$ |  |
|  | $?$ $0$ $2$ |
| $Y$ |  |
|  | $?$ $1$ $0$ |
| $Y$ |  |
|  | $?$ $2$ $0$ |
| $Y$ |  |
|  | $?$ $2$ $2$ |
| $Y$ |  |
|  | $!$ $101$ |

In the following sample, $A = 1$, $B = 2$, and the answer is `Impossible`.

| Input | Output |
| --- | --- |
| $1$ $2$ |  |
|  | $Impossible$ |

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 bool metrics_logged = false;



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 int safe_stoi(const string& s) {
    try {
        size_t idx;
        int val = stoi(s, &idx);
        if (idx != s.size()) return -1; 
        return val;
    } catch (...) {
        return -1; 
    }
}

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

    
    
    int A = inf.readInt();
    int B = inf.readInt();
    string S = inf.readToken();
    
    int N = A + B;
    query_limit = 2 * N;
    
    
    
    bool possible = (A > B); 

    
    if ((int)S.size() != N) {
        finish(_fail, "Generator error: S size does not match A+B");
    }

    
    log_metrics();

    
    cout << A << " " << B << endl;

    
    while (true) {
        
        if (queries > query_limit + 200) {
            finish(_pe, "Too many queries (hard cap)");
        }

        string token;
        if (!(cin >> token)) {
            finish(_pe, "Unexpected EOF (contestant terminated early)");
        }

        
        string up = token;
        for (auto &c : up) c = toupper(c);
        if (up == "IMPOSSIBLE") {
            if (!possible) {
                finish(_ok, "Correctly reported Impossible");
            } else {
                finish(_wa, "Reported Impossible but solution exists (A > B)");
            }
        }

        
        if (token[0] == '!') {
            string ans;
            if (token.size() > 1) {
                ans = token.substr(1);
            } else {
                if (!(cin >> ans)) finish(_pe, "Expected answer string after '!'");
            }

            if (!possible) {
                finish(_wa, "Reported a solution but it was Impossible (A <= B)");
            }

            if (ans.size() != (size_t)N) {
                finish(_pe, "Answer string length mismatch");
            }

            if (ans == S) {
                finish(_ok, "Correct");
            } else {
                finish(_wa, "Incorrect assignment");
            }
        }

        
        bool is_query = false;
        string sa, sb;
        int a = -1, b = -1;

        if (token[0] == '?') {
            is_query = true;
            
            if (token.size() > 1) {
                sa = token.substr(1);
            } else {
                if (!(cin >> sa)) finish(_pe, "Expected a after '?'");
            }
            if (!(cin >> sb)) finish(_pe, "Expected b after a");
        } else {
            
            
            if (isdigit(token[0]) || (token.size() > 1 && token[0] == '-' && isdigit(token[1]))) {
                is_query = true;
                sa = token;
                if (!(cin >> sb)) finish(_pe, "Expected b after a");
            } else {
                finish(_pe, "Invalid token: " + token);
            }
        }

        if (is_query) {
            
            if (!possible) {
                finish(_wa, "Problem is Impossible (A <= B), expected 'Impossible' immediately");
            }

            a = safe_stoi(sa);
            b = safe_stoi(sb);

            if (a < 0 || a >= N || b < 0 || b >= N) {
                finish(_pe, "Query indices out of bounds");
            }

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

            char response = '?';
            
            if (S[a] == '1') {
                
                response = (S[b] == '1' ? 'Y' : 'N');
            } else {
                
                
                
                
                
                response = (S[b] == '1' ? 'N' : 'Y');
            }
            
            cout << response << endl;
        }
    }

    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 = 0;
static bool finished = false;


static int A, B, N;
static vector<int> roles; 


void log_metrics() {
    try {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {}
}


template<typename... Args>
void finish(TResult verdict, const char* fmt, Args... args) {
    if (finished) return;
    finished = true;
    log_metrics();
    quitf(verdict, fmt, args...);
}


string get_reply(int u, int v) {
    
    if (roles[u] == 1) {
        return (roles[v] == 1) ? "Y" : "N";
    }
    
    
    
    
    
    
    else {
        return (roles[v] == 0) ? "Y" : "N";
    }
}

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

    
    
    A = inf.readInt();
    B = inf.readInt();
    N = A + B;
    query_limit = 2LL * N;

    
    
    
    if (!inf.seekEof()) {
        string s = inf.readToken();
        
        if ((int)s.size() == N) {
            for (char c : s) {
                roles.push_back(c - '0');
            }
        } else {
             
             
             roles.clear();
        }
    }
    
    
    if (roles.empty()) {
        roles.assign(N, 0);
        for (int i = 0; i < A; i++) roles[i] = 1;
        shuffle(roles.begin(), roles.end());
    }

    
    cout << A << " " << B << endl;
    log_metrics(); 

    while (true) {
        string token;
        if (!(cin >> token)) {
            finish(_wa, "Unexpected EOF (no solution printed)");
        }

        
        if (token == "Impossible") {
            if (A <= B) finish(_ok, "Correct (Impossible)");
            else finish(_wa, "Reported Impossible but solution exists (A > B)");
        }

        
        if (token[0] == '!') {
            string ans_str;
            if (token.size() > 1) {
                ans_str = token.substr(1);
            } else {
                if (!(cin >> ans_str)) finish(_pe, "EOF after '!'");
            }
            
            if (A <= B) {
                finish(_wa, "Reported solution but expected Impossible (A <= B)");
            }

            if ((int)ans_str.size() != N) {
                finish(_pe, "Answer string length mismatch (expected %d, got %d)", N, (int)ans_str.size());
            }

            bool ok = true;
            for (int i = 0; i < N; i++) {
                int val = ans_str[i] - '0';
                if (val != 0 && val != 1) finish(_pe, "Invalid character in answer string: '%c'", ans_str[i]);
                if (val != roles[i]) ok = false;
            }

            if (ok) finish(_ok, "Correct assignment");
            else finish(_wa, "Incorrect assignment");
        }

        
        
        int u = -1, v = -1;
        bool parse_error = false;

        if (token[0] == '?') {
            if (token.size() > 1) {
                try {
                    u = stoi(token.substr(1));
                } catch (...) { parse_error = true; }
            } else {
                if (!(cin >> u)) parse_error = true;
            }
        } else {
            
            try {
                size_t idx;
                u = stoi(token, &idx);
                if (idx != token.size()) parse_error = true;
            } catch (...) { parse_error = true; }
        }

        if (parse_error) {
            finish(_pe, "Invalid token or format: %s", token.c_str());
        }

        if (!(cin >> v)) {
            finish(_pe, "EOF reading v");
        }

        
        if (u < 0 || u >= N || v < 0 || v >= N) {
            finish(_pe, "Indices out of bounds: %d %d", u, v);
        }

        
        queries++;
        if (queries > 200000) { 
            finish(_pe, "Hard query limit exceeded");
        }
        
        
        string reply = get_reply(u, v);
        cout << reply << endl;
        
        
        if (queries % 100 == 0) log_metrics();
    }

    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");
    
    
    int seed_val = atoi(argv[1]);

    int A = 1, B = 1;

    
    if (seed_val == 1) {
        A = 1; B = 1; 
    } else if (seed_val == 2) {
        A = 1; B = 2; 
    } else if (seed_val == 3) {
        A = 2; B = 1; 
    } else if (seed_val == 4) {
        A = 2000; B = 2000; 
    } else if (seed_val == 5) {
        A = 2000; B = 1999; 
    } else if (seed_val == 6) {
        A = 1000; B = 1000; 
    } else if (seed_val == 7) {
        A = 1001; B = 1000; 
    } else {
        
        
        
        
        
        int type = rnd.next(1, 100);
        
        if (type <= 40) {
            
            
            A = rnd.next(1, 2000);
            B = rnd.next(A, 2000);
        } else if (type <= 70) {
            
            
            B = rnd.next(1, 1999);
            A = B + 1;
        } else {
            
            
            B = rnd.next(1, 1998);
            A = rnd.next(B + 2, 2000);
        }
    }

    
    cout << A << " " << B << endl;

    
    if (mode == "non") {
        string s = "";
        s.reserve(A + B);
        for (int i = 0; i < A; i++) s += '1'; 
        for (int i = 0; i < B; i++) s += '0'; 
        
        
        shuffle(s.begin(), s.end());
        
        cout << s << endl;
    }

    return 0;
}