Problem: icpc2025_asia_east_continent_online_i_f
Difficulty: easy
Categories: greedy, search, game
Time limit: 2000 ms, memory limit: 1024 MB

# This is an interactive problem.

A mischievous robot is navigating an infinitely large 2D grid. However, its movement is confined to the first quadrant, meaning its coordinates $( x , y )$ must always satisfy $x > 0$ and $y > 0$ . Initially, the robot is located at grid coordinates $( s _ { x } , s _ { y } )$ . All grid cells are initially white.

The game proceeds in discrete time steps, up to a maximum of $T = 1 0 0 0$ steps. In each time step, the following sequence occurs:

1. Your Move: You choose integer coordinates $( x _ { m } , y _ { m } )$ such that $1 \leq x _ { m } \leq T$ and $1 \leq y _ { m } \leq T$ . You then mark this cell black. A cell, once marked black, remains black for the rest of the game. You can mark any cell within the range, including the cell where the robot is currently located.

2. Robot’s Move: The robot, currently at position $( r _ { x } , r _ { y } )$ , observes the grid (including the cell you just marked black). It knows the locations of all currently black cells. It then moves to a new position $( n _ { x } , n _ { y } )$ . The new position $( n _ { x } , n _ { y } )$ must be one of the 8 cells immediately adjacent (horizontally, vertically, or diagonally) to $( r _ { x } , r _ { y } )$ . That is, $| n _ { x } - r _ { x } | \le 1$ and $| n _ { y } - r _ { y } | \le 1$ , and $( n _ { x } , n _ { y } ) \neq ( r _ { x } , r _ { y } )$ . Additionally, the robot must stay within the first quadrant, so $n _ { x } > 0$ and $n _ { y } > 0$ . The interactor (controlling the robot) will choose one valid move for the robot. The robot’s strategy is unknown to you.

3. Outcome Check: After the robot moves to $( n _ { x } , n _ { y } )$ , the system checks if the cell $( n _ { x } , n _ { y } )$ is black.

• If $( n _ { x } , n _ { y } )$ is black, the robot explodes.   
• If $( n _ { x } , n _ { y } )$ is white, the game continues to the next time step, with the robot now at $( n _ { x } , n _ { y } )$ .

Your goal is to make the robot explode within $T$ time steps.

# Input

The first line of input contains two integers $s _ { x }$ and $s _ { y }$ ( $1 \leq s _ { x } , s _ { y } \leq 2 0 _ { , }$ ), the initial coordinates of the robot.

# Interaction Protocol

The interaction proceeds in turns for at most $T$ turns. In each turn $t$ (from $t = 1$ to $T$ ):

1. Your program must print one line containing two space-separated integers $x _ { m }$ and $y _ { m }$ , representing the coordinates of the cell you choose to mark black in this turn. Remember to flush the output stream.

2. The interactor reads your chosen coordinates $\left( x _ { m } , y _ { m } \right)$ .

3. The interactor determines the robot’s next move to $( n _ { x } , n _ { y } )$ based on its current position and the set of all black cells (including the one just marked at $( x _ { m } , y _ { m } ) )$ .

4. The interactor checks if the cell $( n _ { x } , n _ { y } )$ is black.

• If it is black (robot explodes), the interactor will print a single line containing $" 0 \ 0 ^ { \prime }$ and terminate. Your program should then read these values and terminate successfully.

• If it is white, the interactor will print a single line containing two space-separated integers $n _ { x }$ and $n _ { y }$ , the new coordinates of the robot. Your program should read these coordinates to know the robot’s current position for the next turn.

If the robot has not exploded after you have made $T$ moves, your program should terminate. Your solution will be judged as incorrect in this case (or if you exceed the turn limit or make an invalid move).

To flush your output, you can use:

• fflush(stdout) (if you use printf) or cout.flush() (if you use cout) in C and C++.   
• System.out.flush() in Java.   
• stdout.flush() in Python.

Note: If your program does not terminate properly, it may be judged as a Presentation Error (PE).

# Example

<table><tr><td>standard input</td><td> standard output</td></tr><tr><td>55</td><td>61</td></tr><tr><td>54</td><td></td></tr><tr><td>53</td><td>41</td></tr><tr><td>52</td><td>62</td></tr><tr><td></td><td>42</td></tr><tr><td>51</td><td></td></tr><tr><td>00</td><td>52</td></tr></table>

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

using namespace std;


static long long queries = 0;
static long long query_limit = 1000;


static int rx, ry;
static set<pair<int, int>> black_cells;
static bool adaptive_mode = false;
static unsigned long long rng_state = 88172645463325252ULL;


unsigned long long next_rng() {
    rng_state ^= (rng_state << 13);
    rng_state ^= (rng_state >> 7);
    rng_state ^= (rng_state << 17);
    return rng_state;
}


long long dist_sq(int x1, int y1, int x2, int y2) {
    long long dx = x1 - x2;
    long long dy = y1 - y2;
    return dx*dx + dy*dy;
}


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


static void cleanup() {
    log_metrics();
}


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

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

    
    
    rx = inf.readInt(1, 20, "sx");
    ry = inf.readInt(1, 20, "sy");
    int mode_val = inf.readInt(0, 1, "is_adaptive");
    adaptive_mode = (mode_val == 1);

    
    log_metrics();
    cout << rx << " " << ry << endl;

    
    while (queries < query_limit) {
        
        string s1;
        if (!(cin >> s1)) {
            finish(_wa, "Unexpected EOF (contestant terminated early)");
        }

        string sx, sy;
        
        if (s1 == "!") {
             finish(_wa, "Contestant output '!', expected coordinates");
        } else if (s1 == "?") {
            if (!(cin >> sx >> sy)) finish(_wa, "EOF after '?'");
        } else {
            sx = s1;
            if (!(cin >> sy)) finish(_wa, "EOF after x coordinate");
        }

        int mx, my;
        try {
            mx = stoi(sx);
            my = stoi(sy);
        } catch (...) {
            finish(_wa, "Invalid integer format in coordinates");
        }

        
        
        if (mx < 1 || mx > 1000 || my < 1 || my > 1000) {
            finish(_wa, format("Coordinate out of bounds: %d %d", mx, my));
        }

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

        black_cells.insert({mx, my});

        
        
        vector<pair<int,int>> valid;
        for(int dx=-1; dx<=1; ++dx){
            for(int dy=-1; dy<=1; ++dy){
                if(!dx && !dy) continue;
                int nx = rx + dx;
                int ny = ry + dy;
                if(nx > 0 && ny > 0) valid.push_back({nx, ny});
            }
        }

        if(valid.empty()) {
            finish(_fail, "Robot stuck (no valid geometric neighbors)");
        }

        
        vector<pair<int,int>> safe, unsafe;
        for(auto p : valid) {
            if(black_cells.count(p)) unsafe.push_back(p);
            else safe.push_back(p);
        }

        pair<int,int> choice = {-1, -1};

        if (safe.empty()) {
            
            
            choice = unsafe[0];
        } else {
            if (!adaptive_mode) {
                
                int idx = next_rng() % safe.size();
                choice = safe[idx];
            } else {
                
                
                long long best_val = -1;
                vector<pair<int,int>> best_opts;
                
                for(auto p : safe) {
                    long long min_d = -1; 
                    for(auto b : black_cells) {
                        long long d = dist_sq(p.first, p.second, b.first, b.second);
                        if(min_d == -1 || d < min_d) min_d = d;
                    }
                    if(min_d > best_val) {
                        best_val = min_d;
                        best_opts.clear();
                        best_opts.push_back(p);
                    } else if(min_d == best_val) {
                        best_opts.push_back(p);
                    }
                }

                
                
                
                long long best_tie = -1;
                pair<int,int> winner = {-1, -1};
                
                for(auto p : best_opts) {
                    long long d_last = dist_sq(p.first, p.second, mx, my);
                    if(d_last > best_tie) {
                        best_tie = d_last;
                        winner = p;
                    } else if (d_last == best_tie) {
                        if(p.first + p.second > winner.first + winner.second) {
                            winner = p;
                        } else if (p.first + p.second == winner.first + winner.second) {
                            if (p.first > winner.first) winner = p;
                        }
                    }
                }
                choice = winner;
            }
        }

        
        bool dead = black_cells.count(choice);
        if(dead) {
            cout << "0 0" << endl;
            finish(_ok, "Robot exploded");
        } else {
            rx = choice.first;
            ry = choice.second;
            cout << rx << " " << ry << endl;
        }
    }

    
    finish(_wa, "Turn limit exceeded (robot survived)");
}


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

using namespace std;


static int queries = 0;
static const int query_limit = 1000;
static const int MAX_COORD = 1000;




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

struct Point {
    int x, y;
    bool operator<(const Point& other) const {
        if (x != other.x) return x < other.x;
        return y < other.y;
    }
    bool operator==(const Point& other) const {
        return x == other.x && y == other.y;
    }
};

set<Point> black_cells;
Point robot_pos;


long long dist_sq(Point a, Point b) {
    long long dx = a.x - b.x;
    long long dy = a.y - b.y;
    return dx * dx + dy * dy;
}



long long get_nearest_black_dist(Point p) {
    if (black_cells.empty()) return 4000000000000000000LL;
    long long min_d = 4000000000000000000LL;
    for (const auto& b : black_cells) {
        min_d = min(min_d, dist_sq(p, b));
    }
    return min_d;
}

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

    
    int sx = inf.readInt();
    int sy = inf.readInt();
    
    
    
    if (!inf.seekEof()) {
        inf.readInt(); 
    }

    
    robot_pos = {sx, sy};
    queries = 0;
    
    
    log_metrics();

    
    cout << sx << " " << sy << endl;

    
    for (int t = 1; t <= query_limit; t++) {
        
        int xm, ym;
        if (!(cin >> xm >> ym)) {
            finish(_pe, "Failed to read user move (EOF or invalid format)");
        }
        
        queries = t;
        
        log_metrics();

        
        if (xm < 1 || xm > MAX_COORD || ym < 1 || ym > MAX_COORD) {
            finish(_pe, format("Invalid coordinates %d %d (must be 1..%d)", xm, ym, MAX_COORD));
        }

        
        black_cells.insert({xm, ym});

        
        vector<Point> candidates;
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) continue;
                int nx = robot_pos.x + dx;
                int ny = robot_pos.y + dy;
                if (nx > 0 && ny > 0) {
                    candidates.push_back({nx, ny});
                }
            }
        }

        
        vector<Point> white, black;
        for (const auto& p : candidates) {
            if (black_cells.count(p)) black.push_back(p);
            else white.push_back(p);
        }

        bool exploded = false;
        Point next_p = {0, 0};

        if (white.empty()) {
            
            if (!black.empty()) {
                next_p = black[0];
                exploded = true;
            } else {
                
                finish(_pe, "Robot has no valid moves");
            }
        } else {
            
            
            
            
            
            
            Point best_p = white[0];
            long long best_d = get_nearest_black_dist(best_p);
            long long best_s = (long long)best_p.x + best_p.y;

            for (size_t i = 1; i < white.size(); i++) {
                Point p = white[i];
                long long d = get_nearest_black_dist(p);
                long long s = (long long)p.x + p.y;
                
                bool better = false;
                if (d > best_d) {
                    better = true;
                } else if (d == best_d) {
                    if (s > best_s) {
                        better = true;
                    } else if (s == best_s) {
                        
                        if (p.x < best_p.x || (p.x == best_p.x && p.y < best_p.y)) {
                            better = true;
                        }
                    }
                }

                if (better) {
                    best_p = p;
                    best_d = d;
                    best_s = s;
                }
            }
            next_p = best_p;
        }

        if (exploded) {
            cout << "0 0" << endl;
            finish(_ok, format("Robot exploded at step %d", t));
        } else {
            cout << next_p.x << " " << next_p.y << endl;
            robot_pos = next_p;
        }
    }

    
    finish(_wa, "Robot survived T steps");
    
    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 is_adaptive = (mode == "adp" ? 1 : 0);

    
    
    long long seed_val = 0;
    string s_arg = argv[1];
    if (!s_arg.empty() && all_of(s_arg.begin(), s_arg.end(), ::isdigit) && s_arg.size() < 18) {
        seed_val = atoll(s_arg.c_str());
    }

    int sx, sy;

    
    if (seed_val == 1) {
        sx = 1; sy = 1; 
    } else if (seed_val == 2) {
        sx = 20; sy = 20; 
    } else if (seed_val == 3) {
        sx = 1; sy = 20; 
    } else if (seed_val == 4) {
        sx = 20; sy = 1; 
    } else if (seed_val == 5) {
        sx = 10; sy = 10; 
    } else {
        
        sx = rnd.next(1, 20);
        sy = rnd.next(1, 20);
    }

    
    
    
    cout << sx << " " << sy << endl;
    cout << is_adaptive << endl;

    return 0;
}