Problem: icpc2025_northwestern_russia_regional_e
Difficulty: medium
Categories: graph, greedy, data structures
Time limit: 4000 ms, memory limit: 1024 MB

This is an interactive problem.

An infinite square grid is hidden from you. Every cell is identified by a pair of integers $( x , y )$ and is randomly colored either black or white with $5 0 \%$ probability for each color, independently of other cells.

Two cells are considered adjacent if they share an edge or a corner. Thus, every cell $( x , y )$ has 8 adjacent cells: $( x - 1 , y - 1 )$ , $( x - 1 , y )$ , $( x - 1 , y + 1 )$ , $( x , y - 1 )$ , $( x , y + 1 )$ , $( x + 1 , y - 1 )$ , $( x + 1 , y )$ , and $( x + 1 , y + 1 )$

A set of cells $S$ is called $\delta$ -connected if for any two cells in $S$ , there exists a path between them using only cells from $S$ , where consecutive cells in the path are adjacent.

In one query, you can learn the color of any cell on the grid. Your task is to find an 8-connected set of $n$ cells such that all cells in the set have the same color.

You need to solve $t$ test cases. In each test case, the grid is colored randomly and independently of the other test cases.

You are allowed to make at most 30 000 queries in total over all test cases.

# Input

The first line contains two integers $t$ and $n$ , denoting the number of test cases and the required size of the 8-connected set ( $1 \leq t \leq 5 0$ ; $2 \leq n \leq 3 0 0$ ).

# Interaction Protocol

In each test case, you can make zero or more queries to learn the colors of grid cells.

To make a query, print a line:

• ? x y

where $( x , y )$ are the coordinates of the requested cell $( - 1 0 ^ { 9 } \leq x , y \leq 1 0 ^ { 9 } ,$ ). After that, read a line containing one letter: $\cdot _ { \tt B } \cdot$ if the cell $( x , y )$ is black, or $" \mathbb { W } ^ { \gamma }$ if the cell $( x , y )$ is white.

Once you are ready to present an 8-connected set of $n$ cells of the same color, print a line:

$\bullet ~ ! ~ c ~ x _ { 1 } ~ y _ { 1 } ~ x _ { 2 } ~ y _ { 2 } ~ . ~ . ~ x _ { n } ~ y _ { n }$

where $c$ is a letter denoting the color of the cells in the set ( $\scriptstyle \mathbf { \tilde { B } } ^ { \prime }$ for black and $" \mathbb { W } ^ { \dag }$ for white), and $( x _ { 1 } , y _ { 1 } ) , ( x _ { 2 } , y _ { 2 } ) , \ldots , ( x _ { n } , y _ { n } )$ are the $n$ distinct cells in the set $( - 1 0 ^ { 9 } \leq x _ { i } , y _ { i } \leq 1 0 ^ { 9 } )$ ). The interactor does not print anything in response to this line.

After printing the set, proceed to the next test case, or terminate the program if this was the last one.

You are allowed to make at most 30 000 queries in total over all test cases (not including the lines that print the sets). If you exceed this limit, the interactor will print 0 instead of its usual response, and your program should terminate immediately to guarantee the “Wrong Answer” verdict.

The interactor is not adaptive: all random grids used in the tests have been pre-generated and remain the same across all submissions.

# Example

<table><tr><td>standard input</td><td>standard output</td></tr><tr><td>25</td><td>？11</td></tr><tr><td>W</td><td></td></tr><tr><td>W</td><td>？12</td></tr><tr><td>B</td><td>？13</td></tr><tr><td>B</td><td>？21</td></tr><tr><td>B</td><td>？22</td></tr><tr><td>W</td><td>？23</td></tr><tr><td>B</td><td>？31</td></tr><tr><td>B</td><td>？32</td></tr><tr><td>B</td><td>？33 !B2213332132</td></tr><tr><td>B</td><td>？11</td></tr><tr><td>W</td><td>？12</td></tr><tr><td>W</td><td>？13</td></tr><tr><td>B</td><td>？21</td></tr><tr><td>B</td><td>？22 ？23</td></tr><tr><td>W</td><td>？31</td></tr><tr><td>W</td><td>？32</td></tr><tr><td>W</td><td>？33</td></tr><tr><td>B</td><td></td></tr><tr><td></td><td>!W1232132331</td></tr><tr><td></td><td></td></tr></table>

# Note

In the example, the queries and the responses are separated by empty lines for clarity. In the actual interaction between your program and the interactor, there will be no empty lines.

Your solution will be evaluated on at most 60 test files.

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


static long long queries = 0;
static long long query_limit = 30000;
static const long long HARD_CAP = 300000; 


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 uint64_t splitmix64(uint64_t z) {
    z += 0x9e3779b97f4a7c15;
    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
    z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
    return z ^ (z >> 31);
}



static char getColor(long long seed, long long x, long long y) {
    uint64_t h = splitmix64((uint64_t)seed);
    h = splitmix64(h ^ (uint64_t)x);
    h = splitmix64(h ^ (uint64_t)y);
    return (h & 1) ? 'W' : 'B';
}

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

    
    int t = inf.readInt();
    int n = inf.readInt();
    inf.readLine(); 

    
    cout << t << " " << n << endl;

    
    for (int i = 0; i < t; i++) {
        
        long long case_seed = inf.readLong();
        inf.readLine(); 

        bool solved_case = false;
        while (!solved_case) {
            
            if (queries > HARD_CAP) {
                finish(_pe, "Hard query limit exceeded (spam protection)");
            }

            
            string token;
            if (!(cin >> token)) {
                finish(_wa, "Unexpected EOF while waiting for command");
            }

            if (token == "!") {
                
                string cStr;
                if (!(cin >> cStr)) finish(_wa, "Unexpected EOF reading answer color");
                
                if (cStr.size() != 1 || (cStr[0] != 'B' && cStr[0] != 'W')) {
                    finish(_wa, "Invalid color format in answer: " + cStr);
                }
                char ansC = cStr[0];

                vector<pair<long long, long long>> cells;
                cells.reserve(n);

                
                for (int k = 0; k < n; k++) {
                    string sx, sy;
                    if (!(cin >> sx >> sy)) finish(_wa, "Unexpected EOF reading answer coordinates");
                    
                    long long x, y;
                    try {
                        x = stoll(sx);
                        y = stoll(sy);
                    } catch (...) {
                        finish(_wa, "Invalid coordinate format in answer");
                    }

                    
                    if (getColor(case_seed, x, y) != ansC) {
                        finish(_wa, format("Cell (%lld, %lld) is not colored %c", x, y, ansC));
                    }
                    cells.push_back({x, y});
                }

                
                vector<pair<long long, long long>> sorted_cells = cells;
                sort(sorted_cells.begin(), sorted_cells.end());
                if (unique(sorted_cells.begin(), sorted_cells.end()) != sorted_cells.end()) {
                    finish(_wa, "Cells in the answer set must be distinct");
                }

                
                
                int visited_count = 0;
                if (n > 0) {
                    vector<bool> vis(n, false);
                    queue<int> q;
                    
                    q.push(0);
                    vis[0] = true;
                    visited_count = 1;

                    while (!q.empty()) {
                        int u = q.front(); q.pop();
                        for (int v = 0; v < n; v++) {
                            if (!vis[v]) {
                                long long dx = abs(cells[u].first - cells[v].first);
                                long long dy = abs(cells[u].second - cells[v].second);
                                
                                if (dx <= 1 && dy <= 1) {
                                    vis[v] = true;
                                    visited_count++;
                                    q.push(v);
                                }
                            }
                        }
                    }
                }

                if (visited_count != n) {
                    finish(_wa, "The set of cells is not 8-connected");
                }

                
                solved_case = true;

            } else {
                
                
                long long x, y;
                
                if (token == "?") {
                    if (!(cin >> x >> y)) finish(_wa, "Unexpected EOF reading query coordinates");
                } else {
                    
                    try {
                        x = stoll(token);
                    } catch (...) {
                        finish(_wa, "Invalid token (expected integer, '?' or '!'): " + token);
                    }
                    if (!(cin >> y)) finish(_wa, "Unexpected EOF reading query coordinate y");
                }

                queries++;
                
                
                if (queries > query_limit) {
                    cout << 0 << endl; 
                    finish(_wa, "Query limit exceeded (max 30000)");
                }

                
                if (queries % 1000 == 0) log_metrics();

                
                char res = getColor(case_seed, x, y);
                cout << res << endl;
            }
        }
    }

    finish(_ok, "All test cases solved successfully");
    return 0;
}


Adaptive interactor (C++):

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 t_opt = opt<int>("t", -1);
    int n_opt = opt<int>("n", -1);

    int t = t_opt;
    int n = n_opt;

    
    long long seed_val = 0;
    if (argc > 1) {
        try {
            seed_val = stoll(string(argv[1]));
        } catch (...) {
            seed_val = 0;
        }
    }

    
    if (t == -1) {
        
        if (n_opt == -1) {
            if (seed_val == 1) t = 50;      
            else if (seed_val == 2) t = 1;  
            else if (seed_val == 3) t = 50; 
            else if (seed_val == 4) t = 1;  
        }

        
        if (t == -1) {
            int p = rnd.next(100);
            if (p < 10) t = 1;            
            else if (p < 25) t = 50;      
            else t = rnd.next(1, 50);     
        }
    }

    
    if (n == -1) {
        
        if (n_opt == -1) {
            if (seed_val == 1) n = 300;     
            else if (seed_val == 2) n = 2;  
            else if (seed_val == 3) n = 2;  
            else if (seed_val == 4) n = 300;
        }

        
        if (n == -1) {
            int p = rnd.next(100);
            if (p < 10) n = 2;            
            else if (p < 25) n = 300;     
            else n = rnd.next(2, 300);    
        }
    }

    
    cout << t << " " << n << endl;

    
    for (int i = 0; i < t; i++) {
        
        long long case_seed = rnd.next(1LL, 4000000000000000000LL);
        
        cout << case_seed;

        if (mode == "adp") {
            
            
            int difficulty = rnd.next(0, 100);
            
            
            
            
            
            int strategy = rnd.next(0, 2);
            
            cout << " " << difficulty << " " << strategy;
        }

        cout << endl;
    }

    return 0;
}