Problem: icpc2023_armenia_regional_i
Difficulty: medium
Categories: graph, bit
Time limit: 2000 ms, memory limit: 1024 MB

This is an interactive problem.

There is an array of $n$ cells, numbered from 1 to $n$ . For each pair of integers $( i , j )$ , where $1 \leq i \leq j \leq n$ , there is a barrier covering all cells from $i$ to $j$ , inclusive. Each barrier is either active or inactive. A cell is visible if there are no active barriers that cover it. Otherwise, the cell is invisible.

The state of each barrier is unknown to you. All you can observe is the number of visible cells. But you can flip the state of any barrier: if it’s active, it turns inactive, and the other way around. Your task is to make all barriers inactive, so that all cells become visible.

# Interaction Protocol

First, read an integer $n$ , denoting the number of cells ( $1 \leq n \leq 1 0$ ).

The following interaction will proceed in rounds. Your program should start each round by reading an integer $k$ , denoting the number of currently visible cells $0 \leq k \leq n$ ).

• If $k = n$ , then the task is done and your program must exit.   
• If $k < n$ , you can flip the state of any barrier. On a separate line, print two integers $i$ and $j$ to flip the state of the $( i , j )$ barrier $1 \leq i \leq j \leq n$ ). After your query, the next round begins, and your program should read a new value of $k$ .

Your solution must make all cells visible using at most 2500 flips. In the beginning, not all cells are visible ( $k < n$ in the first round).

The interactor is not adaptive: in every test, the state of all barriers is chosen before the program execution.

# Example

<table><tr><td>standard input</td><td>standard output</td><td>Initial state</td></tr><tr><td>3</td><td></td><td></td></tr><tr><td>0</td><td>22</td><td></td></tr><tr><td>0</td><td>23</td><td></td></tr><tr><td>1</td><td>12</td><td></td></tr><tr><td>2</td><td></td><td>1 2 3</td></tr><tr><td>3</td><td>22</td><td></td></tr></table>

# Note

In the example, initially, only two barriers, $( 1 , 2 )$ and $( 2 , 3 )$ , are active. These two barriers cover all three cells, so $k$ is equal to $0$ in the first round.

• After flipping the $( 2 , 2 )$ barrier, there are now three active barriers, and still $k = 0$ visible cells.   
• After flipping the $( 1 , 2 )$ barrier, cell 1 becomes visible, so now there is $k = 1$ visible cell.   
• After flipping the $( 2 , 3 )$ barrier, cell 3 also becomes visible. The only invisible cell now is 2, covered by the only active barrier, $( 2 , 2 )$ , and there are $k = 2$ visible cells.   
• After flipping the $( 2 , 2 )$ barrier, all barriers are now inactive, and all cells are visible. After reading $k = 3$ , the program terminates.

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


static long long queries = 0;
static long long query_limit = 2500;
static const long long HARD_CAP = 200000;


int n;
bool active[15][15];


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


int count_visible() {
    int visible = 0;
    for (int c = 1; c <= n; c++) {
        bool covered = false;
        
        for (int i = 1; i <= n; i++) {
            for (int j = i; j <= n; j++) {
                if (active[i][j]) {
                    if (c >= i && c <= j) {
                        covered = true;
                        break;
                    }
                }
            }
            if (covered) break;
        }
        if (!covered) visible++;
    }
    return visible;
}

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

    
    n = inf.readInt(1, 10, "n");
    int m = inf.readInt(0, n * n, "m");

    memset(active, 0, sizeof(active));
    for (int k = 0; k < m; k++) {
        int u = inf.readInt(1, n, "u");
        
        
        int v = inf.readInt(u, n, "v");
        active[u][v] = true;
    }

    
    
    
    query_limit = 2500; 
    log_metrics();

    
    cout << n << endl;

    
    while (true) {
        
        int k = count_visible();
        cout << k << endl;

        
        if (k == n) {
            finish(_ok, "All cells are visible.");
        }

        
        if (queries > HARD_CAP) {
            finish(_pe, "Hard query limit exceeded.");
        }

        
        if (queries % 20 == 0) {
            log_metrics();
        }

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

        int u, v;
        if (token == "?") {
            if (!(cin >> u >> v)) {
                finish(_wa, "Incomplete query parameters after '?'.");
            }
        } else if (token == "!") {
            
            finish(_wa, "Protocol violation: unexpected token '!'.");
            return 0;
        } else {
            
            try {
                u = stoi(token);
            } catch (...) {
                finish(_wa, "Invalid query format: expected integer.");
                return 0;
            }
            if (!(cin >> v)) {
                finish(_wa, "Incomplete query: expected second integer.");
            }
        }

        
        if (u < 1 || u > n || v < 1 || v > n || u > v) {
            finish(_wa, format("Invalid barrier coordinates: %d %d (must be 1 <= i <= j <= n)", u, v));
        }

        
        active[u][v] = !active[u][v];
        queries++;
    }

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

    
    if (n == -1) {
        
        
        if (rnd.next(5) == 0) {
            n = rnd.next(1, 9);
        } else {
            n = 10;
        }
    }

    
    
    if (mode == "adp") {
        cout << n << endl;
        return 0;
    }

    
    
    vector<pair<int, int>> all_barriers;
    for (int i = 1; i <= n; ++i) {
        for (int j = i; j <= n; ++j) {
            all_barriers.push_back({i, j});
        }
    }

    vector<pair<int, int>> active;
    int type = rnd.next(100);

    
    if (type < 5) {
        
        active = all_barriers;
    } else if (type < 15) {
        
        active.push_back(all_barriers[rnd.next(all_barriers.size())]);
    } else if (type < 25) {
        
        vector<pair<int, int>> cands;
        for (auto p : all_barriers) {
            if (p.first == p.second) cands.push_back(p);
        }
        for (auto p : cands) {
            if (rnd.next(2)) active.push_back(p);
        }
    } else if (type < 35) {
        
        vector<pair<int, int>> cands;
        for (auto p : all_barriers) {
            if (p.second - p.first + 1 > n / 2) cands.push_back(p);
        }
        if (cands.empty()) cands = all_barriers;
        for (auto p : cands) {
            if (rnd.next(2)) active.push_back(p);
        }
    } else if (type < 70) {
        
        for (auto p : all_barriers) {
            if (rnd.next(2)) active.push_back(p);
        }
    } else {
        
        for (auto p : all_barriers) {
            if (rnd.next(100) < 20) active.push_back(p);
        }
    }

    
    
    if (active.empty()) {
        active.push_back(all_barriers[rnd.next(all_barriers.size())]);
    }

    
    shuffle(active.begin(), active.end());

    
    
    
    
    cout << n << endl;
    cout << active.size() << endl;
    for (auto p : active) {
        cout << p.first << " " << p.second << endl;
    }

    return 0;
}