Problem: abc278_g
Difficulty: easy
Categories: game, bit
Time limit: 2000 ms, memory limit: 1024 MB

### Problem Statement

This is an **interactive task** (where your program interacts with the judge's program via Standard Input and Output).

You are given integers $N$, $L$, and $R$.  
You play the following game against the judge:

> There are $N$ cards numbered $1$ through $N$ on the table.  
> The players alternately perform the following operation:
>
> * choose an integer pair $(x, y)$ satisfying $1 \leq x \leq N$, $L \leq y \leq R$ such that all of the $y$ cards $x, x+1, \dots, x+y-1$ remain on the table, and remove cards $x, x+1, \dots, x+y-1$ from the table.
>
> The first player to become unable to perform the operation loses, and the other player wins.

Choose whether to go first or second, and play the game against the judge to win.

### Constraints

* $1 \leq N \leq 2000$
* $1 \leq L \leq R \leq N$
* $N$, $L$, and $R$ are integers.

### Input and Output

This is an interactive task (where your program interacts with the judge's program via Standard Input and Output).

Initially, receive $N$, $L$, and $R$, given from the input in the following format:

```
$N$ $L$ $R$
```

First, you choose whether to go first or second. Print `First` if you choose to go first, and `Second` if you choose to go second.

Then, the game immediately starts. If you choose to go first, the judge goes second, and vice versa. You are to interact with the judge via input and output until the game ends to win the game.

In your turn, print an integer pair $(x, y)$ that you choose in the operation in the following format. If there is no $(x, y)$ that you can choose, print $(x, y) = (0, 0)$ instead.

```
$x$ $y$
```

In the judge's turn, the judge print an integer pair $(a, b)$ in the following format:

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

Here, it is guaranteed that $(a, b)$ is of one of the following three kinds.

* If $(a, b) = (0, 0)$: the judge is unable to perform the operation. In other words, you have won the game.
* If $(a, b) = (-1, -1)$: you have chosen an illegal $(x, y)$ or printed $(0, 0)$. In other words, you have lost the game.
* Otherwise: the judge has performed the operation with $(x,y) = (a,b)$. It is guaranteed that judge chooses valid $(x, y)$.

If the judge returns $(a,b)=(0,0)$ or $(a,b)=(-1,-1)$, the game has already ended. In that case, terminate the program immediately.

### Notes

* **After each output, add a newline and then flush Standard Output. Otherwise, you may get a TLE verdict.**
* **If an invalid output is printed during the interaction, or if the program terminates halfway, the verdict will be indeterminate.** Especially, note that if a runtime error occurs during the execution of the program, you may get a WA or TLE verdict instead of a RE verdict.
* Terminate the program immediately after the game ends. Otherwise, the verdict will be indeterminate.

### Sample Interaction

The following is a sample interaction where $N = 6, L = 1$, and $R = 2$.

| Input | Output | Description |
| --- | --- | --- |
| `6 1 2` |  | Initially, you are given integers $N$, $L$, and $R$. |
|  | `First` | You choose to go first and start the game. |
|  | `2 1` | $(x, y) = (2, 1)$ is chosen to remove card $2$. |
| `3 2` |  | $(x, y) = (3, 2)$ is chosen to remove cards $3, 4$. |
|  | `6 1` | $(x, y) = (6, 1)$ is chosen to remove card $6$. |
| `5 1` |  | $(x, y) = (5, 1)$ is chosen to remove card $5$. |
|  | `1 1` | $(x, y) = (1, 1)$ is chosen to remove card $1$. |
| `0 0` |  | The judge is unable to perform the operation, so you win. |

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;


void log_metrics() {
    try {
        tout << "queries=" << 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, L, R;
vector<int> G; 


vector<bitset<2048>> reachable_sets; 
vector<bool> board; 

struct Segment {
    int start;
    int len;
};


void precompute_grundy() {
    G.assign(N + 1, 0);
    reachable_sets.resize(N + 1);
    
    
    
    reachable_sets[0].set(0);

    for (int k = 1; k <= N; ++k) {
        bitset<2048> options;
        
        
        
        
        for (int y = L; y <= R; ++y) {
            int S = k - y;
            if (S < 0) break; 
            options |= reachable_sets[S];
        }

        
        int g = 0;
        while (options.test(g)) g++;
        G[k] = g;

        
        
        
        for (int x = 0; x <= k; ++x) {
            if (k + x > N) break;
            reachable_sets[k + x].set(G[k] ^ G[x]);
        }
    }
}


vector<Segment> get_segments() {
    vector<Segment> segs;
    int current_start = -1;
    int current_len = 0;
    for (int i = 1; i <= N; ++i) {
        if (board[i]) {
            if (current_start == -1) current_start = i;
            current_len++;
        } else {
            if (current_start != -1) {
                segs.push_back({current_start, current_len});
                current_start = -1;
                current_len = 0;
            }
        }
    }
    if (current_start != -1) {
        segs.push_back({current_start, current_len});
    }
    return segs;
}


void play_judge_move() {
    vector<Segment> segs = get_segments();
    int xor_sum = 0;
    for (auto& s : segs) xor_sum ^= G[s.len];

    int best_start = 0;
    int move_y = 0; 
    int move_i = 0; 
    bool found = false;

    
    if (xor_sum != 0) {
        for (auto& s : segs) {
            int target = G[s.len] ^ xor_sum;
            
            
            
            for (int y = L; y <= R; ++y) {
                int rem = s.len - y;
                if (rem < 0) break;
                
                if (reachable_sets[rem].test(target)) {
                    
                    for (int i = 0; i <= rem; ++i) {
                        int j = rem - i;
                        if ((G[i] ^ G[j]) == target) {
                            best_start = s.start;
                            move_y = y;
                            move_i = i;
                            found = true;
                            goto done;
                        }
                    }
                }
            }
        }
    } 
    
    
    
    if (!found) {
        for (auto& s : segs) {
            if (s.len >= L) {
                best_start = s.start;
                move_y = L; 
                move_i = 0;
                found = true;
                goto done;
            }
        }
    }

done:
    if (!found) {
        
        cout << "0 0" << endl; 
        finish(_ok, "Judge unable to move, Contestant wins");
    } else {
        
        int x = best_start + move_i;
        int y = move_y;
        
        
        for (int k = 0; k < y; ++k) board[x + k] = false;
        
        cout << x << " " << y << endl;
        queries++;
        log_metrics();
    }
}

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

    
    N = inf.readInt(1, 2000, "N");
    L = inf.readInt(1, N, "L");
    R = inf.readInt(L, N, "R");
    
    
    query_limit = N + 100;
    log_metrics();

    
    precompute_grundy();
    board.assign(N + 1, true);

    
    cout << N << " " << L << " " << R << endl;

    
    string side = "";
    if (!(cin >> side)) {
        finish(_wa, "Cannot read side choice");
    }
    
    bool contestant_turn = false;
    if (side == "First") {
        contestant_turn = true;
    } else if (side == "Second") {
        contestant_turn = false;
    } else {
        finish(_wa, "Invalid side choice (expected First/Second): " + side);
    }

    
    int max_turns = 5000; 
    while (max_turns--) {
        if (contestant_turn) {
            
            string t1;
            if (!(cin >> t1)) {
                 finish(_wa, "Unexpected EOF reading move");
            }
            
            int x = -1, y = -1;
            
            if (t1 == "?") {
                if (!(cin >> x >> y)) finish(_wa, "Bad format after ?");
            } else if (t1 == "!") {
                finish(_wa, "Unexpected '!' output");
            } else {
                try {
                    x = stoi(t1);
                } catch (...) {
                    finish(_wa, "Token not integer: " + t1);
                }
                if (!(cin >> y)) finish(_wa, "Cannot read y");
            }

            
            if (x == 0 && y == 0) {
                cout << "-1 -1" << endl; 
                finish(_wa, "Contestant output 0 0 (resignation)");
            }

            
            if (x < 1 || x > N || y < L || y > R) {
                cout << "-1 -1" << endl;
                finish(_wa, format("Invalid range: x=%d y=%d (N=%d, L=%d, R=%d)", x, y, N, L, R));
            }
            
            bool possible = true;
            for (int k = 0; k < y; ++k) {
                if (x + k > N || !board[x + k]) {
                    possible = false;
                    break;
                }
            }
            if (!possible) {
                cout << "-1 -1" << endl;
                finish(_wa, format("Invalid move: cards overlap or removed at x=%d y=%d", x, y));
            }

            
            for (int k = 0; k < y; ++k) board[x + k] = false;
            queries++;
            log_metrics();
            
            contestant_turn = false;

        } else {
            play_judge_move();
            contestant_turn = true;
        }
    }
    
    finish(_pe, "Game limit exceeded");
    return 0;
}


Adaptive interactor (C++):






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

using namespace std;


const int MAXN = 2005;
const int MAX_VAL = 2048; 


int N, L, R;
int G[MAXN]; 




int can_make_split[MAXN][MAX_VAL]; 


int freq[MAX_VAL];


set<pair<int,int>> intervals;


long long queries = 0;
long long query_limit = 0;


void log_metrics() {
    if (query_limit > 0) {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    }
}


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


void precompute() {
    
    for(int i=0; i<MAXN; ++i) {
        for(int j=0; j<MAX_VAL; ++j) {
            can_make_split[i][j] = -1;
        }
    }

    
    G[0] = 0;
    can_make_split[0][0] = 0; 

    memset(freq, 0, sizeof(freq));
    
    
    int current_window_start = 1 - R; 
    int current_window_end = 1 - L;   

    
    for (int k = 1; k <= N; ++k) {
        
        
        
        
        

        int target_start = k - R;
        int target_end = k - L;
        
        
        while (current_window_end < target_end) {
            current_window_end++;
            int rem = current_window_end;
            if (rem >= 0) {
                for (int v = 0; v < MAX_VAL; ++v) {
                    if (can_make_split[rem][v] != -1) freq[v]++;
                }
            }
        }
        
        
        while (current_window_start < target_start) {
            int rem = current_window_start;
            if (rem >= 0) {
                for (int v = 0; v < MAX_VAL; ++v) {
                    if (can_make_split[rem][v] != -1) freq[v]--;
                }
            }
            current_window_start++;
        }
        
        
        int mex = 0;
        while (freq[mex] > 0) mex++;
        G[k] = mex;
        
        
        
        for (int s = 0; s <= k; ++s) {
            int val = G[s] ^ G[k - s];
            if (val < MAX_VAL) {
                
                if (can_make_split[k][val] == -1) {
                    can_make_split[k][val] = s;
                }
            }
        }
    }
}



bool remove_interval(int x, int y) {
    int l = x;
    int r = x + y - 1;
    
    
    auto it = intervals.upper_bound({l, 2000000000});
    if (it == intervals.begin()) return false;
    it--;
    
    pair<int, int> cur = *it;
    
    
    if (cur.first <= l && cur.second >= r) {
        intervals.erase(it);
        
        
        if (l > cur.first) {
            intervals.insert({cur.first, l - 1});
        }
        
        if (r < cur.second) {
            intervals.insert({r + 1, cur.second});
        }
        return true;
    }
    return false;
}

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

    
    N = inf.readInt();
    L = inf.readInt();
    R = inf.readInt();

    
    query_limit = N; 
    log_metrics();

    
    precompute();

    
    cout << N << " " << L << " " << R << endl;

    
    intervals.insert({1, N});

    
    string side;
    if (!(cin >> side)) {
        finish_interaction(_pe, "No side choice provided");
    }

    bool my_turn = false;
    if (side == "First") {
        my_turn = false; 
    } else if (side == "Second") {
        my_turn = true;  
    } else {
        finish_interaction(_pe, "Invalid side choice: " + side);
    }

    
    while (true) {
        
        if (queries > 2 * N + 200) {
            finish_interaction(_pe, "Too many moves/Loop detected");
        }

        if (my_turn) {
            
            
            
            int nim_sum = 0;
            for (auto p : intervals) {
                nim_sum ^= G[p.second - p.first + 1];
            }

            int chosen_x = -1, chosen_y = -1;
            bool found = false;

            if (nim_sum != 0) {
                
                for (auto p : intervals) {
                    int len = p.second - p.first + 1;
                    int target = G[len] ^ nim_sum;
                    
                    
                    
                    if (target < G[len]) {
                        
                        
                        
                        int min_rem = max(0, len - R);
                        int max_rem = len - L;
                        
                        for (int rem = min_rem; rem <= max_rem; ++rem) {
                            if (can_make_split[rem][target] != -1) {
                                int s = can_make_split[rem][target];
                                
                                
                                chosen_y = len - rem;
                                chosen_x = p.first + s;
                                found = true;
                                break;
                            }
                        }
                    }
                    if (found) break;
                }
            }
            
            if (!found) {
                
                
                for (auto p : intervals) {
                    if (p.second - p.first + 1 >= L) {
                        chosen_x = p.first;
                        chosen_y = L;
                        found = true;
                        break;
                    }
                }
            }

            if (!found) {
                
                cout << "0 0" << endl;
                finish_interaction(_ok, "Judge has no moves (Contestant wins)");
            } else {
                
                remove_interval(chosen_x, chosen_y);
                cout << chosen_x << " " << chosen_y << endl;
                my_turn = false;
            }

        } else {
            
            int x, y;
            if (!(cin >> x >> y)) {
                finish_interaction(_wa, "Unexpected EOF while reading contestant move");
            }
            queries++;

            
            if (x == 0 && y == 0) {
                cout << "-1 -1" << endl;
                finish_interaction(_wa, "Contestant resigned (0 0)");
            }

            
            if (x < 1 || x > N || y < L || y > R) {
                cout << "-1 -1" << endl;
                finish_interaction(_wa, "Move parameters out of bounds");
            }

            
            if (!remove_interval(x, y)) {
                cout << "-1 -1" << endl;
                finish_interaction(_wa, "Invalid move: cards not present on table");
            }
            
            my_turn = true;
        }
    }

    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");

    
    long long seedVal = -1;
    try {
        string s(argv[1]);
        if (!s.empty() && all_of(s.begin(), s.end(), ::isdigit)) {
            seedVal = stoll(s);
        }
    } catch (...) {
        seedVal = -1;
    }

    int n, l, r;

    
    if (seedVal >= 1 && seedVal <= 5) {
        if (seedVal == 1) {
            
            n = 1; l = 1; r = 1;
        } else if (seedVal == 2) {
            
            n = 2000; l = 1; r = 1;
        } else if (seedVal == 3) {
            
            n = 2000; l = 1; r = 2000;
        } else if (seedVal == 4) {
            
            n = 2000; l = 1000; r = 1000;
        } else {
            
            n = 6; l = 1; r = 2;
        }
    } else {
        
        
        if (rnd.next(4) == 0) {
            n = rnd.next(1, 50);
        } else {
            n = rnd.next(1800, 2000);
        }

        
        int type = rnd.next(100);
        if (type < 20) {
            
            l = rnd.next(1, n);
            r = l;
        } else if (type < 40) {
            
            l = 1;
            r = rnd.next(l, n);
        } else if (type < 60) {
            
            l = rnd.next(1, n);
            r = n;
        } else if (type < 80) {
            
            l = rnd.next(1, n);
            r = min(n, l + rnd.next(0, 50));
        } else {
            
            l = rnd.next(1, n);
            r = rnd.next(l, n);
        }
    }

    
    cout << n << " " << l << " " << r << endl;

    return 0;
}