Problem: cf1442_f
Difficulty: hard
Categories: graph, bit
Time limit: 2000 ms, memory limit: 512 MB

This is an interactive problem

Ginny is taking an exam on game theory. The professor is tired of hearing the same answers over and over again, so he offered Ginny to play a game instead of a standard exam.

As known from the course, a combinatorial game on a graph with multiple starting positions is a game with a directed graph and multiple starting vertices holding a token each. Two players take turns moving one of the tokens along the graph edges on each turn. The player who can't make a move loses the game. If both players can play an infinitely long game without losing, a draw is called.

For the exam, the professor drew an acyclic directed graph and chose one of its vertices. Ginny needs to guess the vertex the professor chose. To do so, Ginny can choose a multiset of vertices $S$ several times and ask the professor: "If I put one token in each vertex of the given graph for each occurrence of the vertex in the multiset $S$, and then one more in the selected vertex, what would be the result of the combinatorial game?".

Having given the task, the professor left the room to give Ginny some time to prepare for the game. Ginny thinks that she's being tricked because the problem is impossible to solve. Therefore, while the professor is away, she wants to add or remove several edges from the graph. Even though the original graph was acyclic, edges could be added to the graph to make cycles appear.

Interaction

In this task, interaction consists of several phases.

In the first phase, the interactor gives as an input to your program three integers $N$ ($1 \le N \le 1000$), $M$ ($0 \le M \le 100\,000$), $T$ ($1 \le T \le 2000$): the number of vertices and edges in the initial graph, and the number of times Ginny has to guess the chosen vertex. The next $M$ lines contain pairs of vertices $a_i$ $b_i$ ($1 \le a_i, b_i \le N$): beginning and end of corresponding graph edges. The graph is guaranteed to be acyclic and all of its edges to be distinct.

The solution should print an integer $K$ ($0 \le K \le 4242$): the number of edges to change in the graph. The next $K$ lines should contain either "+ $a_i$ $b_i$" or "- $a_i$ $b_i$": the beginning and the end of an edge that Ginny has to add or remove accordingly. You are allowed to add preexisting edges to the graph. Operations are performed in the order of appearance, so Ginny is allowed to remove an edge added by the solution. You can only remove an existing edge. The operations can create cycles in the graph.

The next $T$ phases are dedicated to guessing the chosen vertices. In each phase, the solution can make at most 20 queries and then print the answer. To query a multiset $S$, the solution should print "? $|S|~S_1~S_2~\dots~S_{|S|}$". The total size of all multisets in a single phase should not exceed 20. The interactor will reply with one of the following words:

* "Win", if the winner of a combinatorial game with tokens in multiset $S$ and the selected vertex is the first player.
* "Lose", if the winner of a combinatorial game with tokens in multiset $S$ and the selected vertex is the second player.
* "Draw", if a combinatorial game with tokens in multiset $S$ and selected vertex ends in a draw.
* "Slow", if the solution made a 21-st request, or the total size of all multisets in a single phase exceeded 20. In this case, the solution should terminate and receive Wrong Answer verdict.

As soon as the selected vertex is guessed, that solution should print "! v". If the chosen vertex is guessed correctly, the interactor will print Correct and the solution should either move on to the next phase of guessing or finish its execution if it's the last phase. Otherwise, the interactor will print Wrong, which means that the solution should terminate and will receive the Wrong Answer verdict.

The interactor can change the chosen vertex based on graph changes and solution actions, but at every given moment of time, at least one vertex that corresponds to all given interactor answers will exist.

Example

Input

```
3 2 3
1 2
2 3

Lose

Correct

Win

Correct

Draw

Correct
```

Output

```
6
+ 2 2
- 1 2
+ 2 3
- 2 2
+ 3 1
+ 2 2
? 0

! 1

? 1 2

! 3

? 5 1 3 1 3 1

! 2
```

Note

In the sample test, the empty lines represent waiting for the input by the other side of the interaction. The real interactor will not print empty lines, and the solution should not print them either.

 ![](https://espresso.codeforces.com/8df35feeaefb9caf3364e8bd7315ef9ff2eaed84.png) 

The image above illustrates the sample test. Added edges are coloured in red, and the removed edges are drawn with a dotted line. Three guessing phases denote different ways of getting the answer.

* If the solution will query just the chosen vertex, the interactor will return the result of the game in that vertex. The first player loses only if the chosen vertex has the number $1$.
* If we add a single vertex $2$ to the chosen vertex, then if the chosen vertex is either $1$ or $2$, the game should end in a draw. If vertex number $3$ is chosen, then the first player wins.
* If we place three tokens in vertex $1$ and two tokens in vertex $3$, then the game will end in a draw only if vertex $2$ is chosen. If the professor chose vertex $3$, the first player will win, if the professor chose vertex $1$, then the second player will win.

In the first test, the interactor will behave as if the chosen vertices are the same as those in the example above. However, if you will try to guess the answer before it limits the options to one single vertex, the solution will get "Wrong Answer", even if you print the same answers. That's because the interactor is allowed to change the chosen vertex if it's consistent with the previous query answers.

Non-adaptive interactor (C++):







#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;

static const int MAX_N = 1005;
static bool adj[MAX_N][MAX_N];
static vector<int> adj_list[MAX_N];
static int N, M, T;
static vector<int> targets;
static int in_degree[MAX_N];
static int grundy[MAX_N];
static bool is_dag = false;


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_verdict(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}



void check_graph() {
    for(int i = 1; i <= N; ++i) {
        adj_list[i].clear();
        in_degree[i] = 0;
    }
    for(int i = 1; i <= N; ++i) {
        for(int j = 1; j <= N; ++j) {
            if(adj[i][j]) {
                adj_list[i].push_back(j);
                in_degree[j]++;
            }
        }
    }

    queue<int> q;
    vector<int> topo;
    vector<int> deg(N + 1);
    for(int i = 1; i <= N; ++i) {
        deg[i] = in_degree[i];
        if(deg[i] == 0) q.push(i);
    }

    while(!q.empty()) {
        int u = q.front(); q.pop();
        topo.push_back(u);
        for(int v : adj_list[u]) {
            deg[v]--;
            if(deg[v] == 0) q.push(v);
        }
    }

    if((int)topo.size() == N) {
        is_dag = true;
        
        for(int i = N - 1; i >= 0; --i) {
            int u = topo[i];
            set<int> seen;
            for(int v : adj_list[u]) seen.insert(grundy[v]);
            int g = 0;
            while(seen.count(g)) g++;
            grundy[u] = g;
        }
    } else {
        is_dag = false;
    }
}




static map<vector<int>, int> memo;

int solve_cyclic(vector<int> state) {
    sort(state.begin(), state.end());
    if(memo.count(state)) {
        int val = memo[state];
        if(val == -1) return 2; 
        return val;
    }

    memo[state] = -1; 

    bool can_reach_lose = false; 
    bool can_reach_draw = false; 

    
    vector<int> unique_pos;
    if(!state.empty()) {
        unique_pos.push_back(state[0]);
        for(size_t i = 1; i < state.size(); ++i) {
            if(state[i] != state[i-1]) unique_pos.push_back(state[i]);
        }
    }

    for(int u : unique_pos) {
        for(int v : adj_list[u]) {
            vector<int> next_state = state;
            
            auto it = lower_bound(next_state.begin(), next_state.end(), u);
            *it = v;
            
            int res = solve_cyclic(next_state);
            
            if(res == 0) { 
                can_reach_lose = true;
                break; 
            }
            if(res == 2) {
                can_reach_draw = true;
            }
        }
        if(can_reach_lose) break;
    }

    int res;
    if(can_reach_lose) res = 1; 
    else if(can_reach_draw) res = 2; 
    else res = 0; 

    memo[state] = res;
    return res;
}

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

    
    N = inf.readInt(1, 1000, "N");
    M = inf.readInt(0, 100000, "M");
    T = inf.readInt(1, 2000, "T");
    query_limit = 20LL * T;

    vector<pair<int,int>> input_edges;
    for(int i = 0; i < M; ++i) {
        int u = inf.readInt(1, N, "u");
        int v = inf.readInt(1, N, "v");
        input_edges.push_back({u, v});
        adj[u][v] = true;
    }

    for(int i = 0; i < T; ++i) {
        targets.push_back(inf.readInt(1, N, "target"));
    }

    
    cout << N << " " << M << " " << T << endl;
    for(auto &e : input_edges) {
        cout << e.first << " " << e.second << endl;
    }
    cout.flush();

    
    int K;
    if(!(cin >> K)) finish_verdict(_wa, "Failed to read K");
    if(K < 0 || K > 4242) finish_verdict(_wa, "K out of range");

    for(int k = 0; k < K; ++k) {
        string type;
        int u, v;
        if(!(cin >> type >> u >> v)) finish_verdict(_wa, "Failed to read operation");
        if(u < 1 || u > N || v < 1 || v > N) finish_verdict(_wa, "Vertex index out of range");
        
        if(type == "+") {
            adj[u][v] = true;
        } else if(type == "-") {
            if(!adj[u][v]) finish_verdict(_wa, "Attempt to remove non-existing edge");
            adj[u][v] = false;
        } else {
            finish_verdict(_wa, "Invalid operation type");
        }
    }

    
    check_graph();

    
    for(int phase = 0; phase < T; ++phase) {
        int target = targets[phase];
        int phase_queries = 0;
        int sum_sizes = 0;

        while(true) {
            string token;
            if(!(cin >> token)) finish_verdict(_wa, "Unexpected EOF during interaction");

            if(token == "!") {
                int guess;
                if(!(cin >> guess)) finish_verdict(_wa, "Failed to read guess");
                if(guess == target) {
                    cout << "Correct" << endl;
                    break; 
                } else {
                    cout << "Wrong" << endl;
                    finish_verdict(_wa, "Wrong guess");
                }
            } else if(token == "?") {
                phase_queries++;
                queries++;
                
                int k;
                if(!(cin >> k)) finish_verdict(_wa, "Failed to read multiset size");
                sum_sizes += k;
                
                vector<int> s;
                for(int i = 0; i < k; ++i) {
                    int val;
                    if(!(cin >> val)) finish_verdict(_wa, "Failed to read multiset element");
                    s.push_back(val);
                }

                
                
                
                if(phase_queries > 20 || sum_sizes > 20) {
                    cout << "Slow" << endl;
                    finish_verdict(_wa, "Too many queries or multiset size limit exceeded");
                }

                int res = 0; 
                if(is_dag) {
                    
                    int x = grundy[target];
                    for(int val : s) x ^= grundy[val];
                    res = (x > 0 ? 1 : 0);
                } else {
                    
                    s.push_back(target);
                    res = solve_cyclic(s);
                }

                if(res == 1) cout << "Win" << endl;
                else if(res == 0) cout << "Lose" << endl;
                else cout << "Draw" << endl;
                
                cout.flush();
            } else {
                finish_verdict(_wa, "Invalid protocol token (expected '?' or '!')");
            }
        }
    }

    finish_verdict(_ok, "Passed all phases");
    return 0;
}


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

static long long total_queries = 0;
static long long query_limit = 0;

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

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

int N, M, T;
vector<pair<int,int>> initial_edges;
vector<vector<int>> adj;
vector<int> sg;
vector<vector<int>> reach_vals; 




vector<int> candidates;
vector<bool> is_candidate;

void compute_sg() {
    
    vector<int> out_degree(N + 1, 0);
    vector<vector<int>> rev_adj(N + 1);
    
    for(int u = 1; u <= N; ++u) {
        out_degree[u] = adj[u].size();
        for(int v : adj[u]) {
            rev_adj[v].push_back(u);
        }
    }
    
    sg.assign(N + 1, -1);
    
    
    
    vector<int> rem_out = out_degree;
    queue<int> q;
    
    for(int i = 1; i <= N; ++i) {
        if(out_degree[i] == 0) {
            sg[i] = 0;
            q.push(i);
        }
    }
    
    while(!q.empty()) {
        int v = q.front(); q.pop();
        
        for(int u : rev_adj[v]) {
            rem_out[u]--;
            if(rem_out[u] == 0) {
                
                vector<int> seen;
                seen.reserve(adj[u].size());
                for(int w : adj[u]) {
                    if(sg[w] != -1) seen.push_back(sg[w]);
                }
                sort(seen.begin(), seen.end());
                seen.erase(unique(seen.begin(), seen.end()), seen.end());
                
                int mex = 0;
                for(int x : seen) {
                    if(x == mex) mex++;
                    else if(x > mex) break;
                }
                sg[u] = mex;
                q.push(u);
            }
        }
    }
    
    
    reach_vals.assign(N + 1, vector<int>());
    for(int u = 1; u <= N; ++u) {
        if(sg[u] == -1) {
            for(int v : adj[u]) {
                if(sg[v] != -1) {
                    reach_vals[u].push_back(sg[v]);
                }
            }
            sort(reach_vals[u].begin(), reach_vals[u].end());
            reach_vals[u].erase(unique(reach_vals[u].begin(), reach_vals[u].end()), reach_vals[u].end());
        }
    }
}








int solve_game(const vector<int>& S, int hidden) {
    int undef_cnt = 0;
    int xor_sum = 0;
    int bad_node = -1;
    
    auto process = [&](int u) {
        if(sg[u] == -1) {
            undef_cnt++;
            bad_node = u;
        } else {
            xor_sum ^= sg[u];
        }
    };
    
    for(int u : S) process(u);
    process(hidden);
    
    if(undef_cnt == 0) {
        return (xor_sum != 0) ? 0 : 1;
    } else if(undef_cnt > 1) {
        return 2;
    } else {
        
        
        
        
        const auto& rv = reach_vals[bad_node];
        bool can_win = binary_search(rv.begin(), rv.end(), xor_sum);
        return can_win ? 0 : 2;
    }
}

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

    N = inf.readInt();
    M = inf.readInt();
    T = inf.readInt();
    for(int i = 0; i < M; ++i) {
        int u = inf.readInt();
        int v = inf.readInt();
        initial_edges.push_back({u, v});
    }

    query_limit = (long long)T * 20;

    cout << N << " " << M << " " << T << endl;
    for(auto& e : initial_edges) {
        cout << e.first << " " << e.second << endl;
    }
    cout.flush();

    
    int K;
    if(!(cin >> K)) finish(_wa, "Cannot read K");
    if(K < 0 || K > 4242) finish(_wa, "K out of range");
    
    set<pair<int,int>> current_edges(initial_edges.begin(), initial_edges.end());
    
    for(int i = 0; i < K; ++i) {
        string type_str;
        int u, v;
        if(!(cin >> type_str >> u >> v)) finish(_wa, "Cannot read op");
        if(u < 1 || u > N || v < 1 || v > N) finish(_wa, "Vertex out of range in op");
        
        if(type_str == "+") {
            current_edges.insert({u, v});
        } else if(type_str == "-") {
            current_edges.erase({u, v});
        } else {
            finish(_wa, "Invalid op type");
        }
    }
    
    
    adj.assign(N + 1, vector<int>());
    for(auto& e : current_edges) {
        adj[e.first].push_back(e.second);
    }
    
    compute_sg();
    
    
    is_candidate.assign(N + 1, true);

    for(int t = 0; t < T; ++t) {
        
        candidates.clear();
        for(int i = 1; i <= N; ++i) candidates.push_back(i);
        is_candidate.assign(N + 1, true);

        int phase_queries = 0;
        int phase_size_sum = 0;
        bool solved = false;

        while(true) {
            string token;
            if(!(cin >> token)) finish(_wa, "Unexpected EOF during interaction");
            
            if(token == "!") {
                int guess;
                if(!(cin >> guess)) finish(_wa, "No guess provided");
                
                
                
                
                
                if(guess >= 1 && guess <= N && is_candidate[guess]) {
                    if(candidates.size() == 1) {
                        cout << "Correct" << endl;
                        solved = true;
                        break;
                    } else {
                        cout << "Wrong" << endl;
                        finish(_wa, "Ambiguous guess (adaptive)");
                    }
                } else {
                    cout << "Wrong" << endl;
                    finish(_wa, "Guess inconsistent with history");
                }
            } else if(token == "?") {
                total_queries++;
                phase_queries++;
                
                int k;
                if(!(cin >> k)) finish(_wa, "Cannot read set size");
                
                phase_size_sum += k;
                
                vector<int> S(k);
                for(int i = 0; i < k; ++i) {
                    cin >> S[i];
                    if(S[i] < 1 || S[i] > N) finish(_wa, "Vertex in query out of range");
                }
                
                if(phase_queries > 20 || phase_size_sum > 20) {
                    cout << "Slow" << endl;
                    finish(_wa, "Phase budget exceeded");
                }
                
                
                int counts[3] = {0, 0, 0}; 
                for(int h : candidates) {
                    counts[solve_game(S, h)]++;
                }
                
                
                int best_resp = -1;
                int max_c = -1;
                for(int r = 0; r < 3; ++r) {
                    if(counts[r] > max_c) {
                        max_c = counts[r];
                        best_resp = r;
                    }
                }
                
                if(max_c <= 0) {
                    finish(_wa, "No consistent hidden vertex exists (internal error or empty candidate set)");
                }
                
                if(best_resp == 0) cout << "Win" << endl;
                else if(best_resp == 1) cout << "Lose" << endl;
                else cout << "Draw" << endl;
                
                
                vector<int> next_cand;
                next_cand.reserve(max_c);
                for(int h : candidates) {
                    if(solve_game(S, h) == best_resp) {
                        next_cand.push_back(h);
                    } else {
                        is_candidate[h] = false;
                    }
                }
                candidates = next_cand;
            } else {
                finish(_wa, "Invalid token " + token);
            }
        }
        if(!solved) finish(_wa, "Phase ended without correct guess");
    }

    finish(_ok, "All phases passed");
}


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");
    
    
    long long seed_val = 0;
    if (argc > 1) {
        seed_val = atoll(argv[1]);
    }

    int N = -1, M = -1, T = -1;
    
    int n_arg = opt<int>("n", -1);
    int m_arg = opt<int>("m", -1);
    int t_arg = opt<int>("t", -1);

    if (n_arg != -1) {
        N = n_arg;
        long long max_edges = 1LL * N * (N - 1) / 2;
        if (m_arg != -1) M = m_arg;
        else M = rnd.next(0LL, min((long long)100000, max_edges));
        
        if (t_arg != -1) T = t_arg;
        else T = rnd.next(1, 2000);
    } else {
        
        if (seed_val == 1) {
            N = 3; M = 2; T = 3; 
        } else if (seed_val == 2) {
            N = 1000; M = 0; T = 1; 
        } else if (seed_val == 3) {
            N = 1000; M = 100000; T = 2000; 
        } else {
            N = rnd.next(2, 1000);
            
            long long max_E = 1LL * N * (N - 1) / 2;
            long long cap_M = min((long long)100000, max_E);
            
            
            int type = rnd.next(1, 10);
            if (type == 1) M = 0;
            else if (type <= 4) M = rnd.next(1LL, min(cap_M, (long long)N * 2));
            else if (type <= 8) M = rnd.next(min(cap_M, (long long)N * 2), cap_M);
            else M = cap_M;
            
            T = rnd.next(1, 2000);
        }
    }

    
    N = max(1, min(1000, N));
    long long max_edges = 1LL * N * (N - 1) / 2;
    M = max(0, min((int)min((long long)100000, max_edges), M));
    T = max(1, min(2000, T));

    
    
    vector<int> p(N);
    iota(p.begin(), p.end(), 1);
    shuffle(p.begin(), p.end());

    
    vector<pair<int,int>> final_edges;
    
    
    
    if (max_edges <= 200000 && M > max_edges / 2) {
        vector<pair<int,int>> all_edges;
        all_edges.reserve(max_edges);
        for (int i = 0; i < N; ++i) {
            for (int j = i + 1; j < N; ++j) {
                
                all_edges.push_back({p[i], p[j]});
            }
        }
        shuffle(all_edges.begin(), all_edges.end());
        for (int i = 0; i < M; ++i) final_edges.push_back(all_edges[i]);
    } else {
        set<pair<int,int>> distinct_edges;
        while ((int)distinct_edges.size() < M) {
            int u = rnd.next(0, N - 1);
            int v = rnd.next(0, N - 1);
            if (u == v) continue;
            
            if (u > v) swap(u, v);
            distinct_edges.insert({p[u], p[v]});
        }
        for (auto &e : distinct_edges) final_edges.push_back(e);
    }
    
    shuffle(final_edges.begin(), final_edges.end());

    
    println(N, M, T);
    for (auto &e : final_edges) {
        println(e.first, e.second);
    }

    if (mode == "non") {
        vector<int> targets(T);
        for (int i = 0; i < T; ++i) {
            targets[i] = rnd.next(1, N);
        }
        println(targets);
    } else if (mode == "adp") {
        println(-1);
    }

    return 0;
}