Problem: icpc2022_swerc_i
Difficulty: medium
Categories: greedy, data structures, game
Time limit: 2000 ms, memory limit: 2048 MB

Alessia and Bernardo are discovering the world of competitive programming through the books of their university library.

The library consists of $m$ sections numbered from 1 to $m$ . Each section contains only books dedicated to a particular subject and different sections correspond to different subjects. In order to prevent the students from wandering in the library, the university has established a system of passes. Each pass has a length $y$ associated to it and allows access to an interval of $y$ consecutive sections in the library. During a visit, the student must choose exactly one book from one of these sections and leave the library. Each pass can be used only once.

At the moment Alessia and Bernardo have $n$ passes of lengths $x _ { 1 }$ , $x _ { 2 }$ , . . . , $x _ { n }$ . They have different opinions on the best way to improve: Alessia thinks that it is important to study many different topics, while Bernardo believes that it is important to study deeply at least one topic. So, Alessia wants to use the $n$ passes to get $n$ books on distinct topics, while Bernardo would like to get at least two books on the same topic.

They have reached the following agreement: for each of the following $n$ days, Alessia will choose a pass of length $y$ among those which are still available and an interval of $y$ sections in the library, and Bernardo will go into the library and will take exactly one book from one of those sections.

Can Bernardo manage to get at least two books on the same subject, or will Alessia be able to avoid it?

You should decide whether you want to be Alessia or Bernardo, and you have to fulfill the goal of your chosen character. The judge will impersonate the other character. Note that, even if at some moment Bernardo has already taken two books on the same subject, the interaction should go on until the end of the $n$ days.

# Input

The first line contains two integers $n$ and $m$ ( $1 \leq n \leq 1 0 0$ , $n \leq m \leq 5 0 0 0$ ) — the number of passes and the number of sections.

The second line contains $n$ integers $x _ { 1 }$ , $x _ { 2 }$ , . . . , $x _ { n }$ $\mathrm { ~ 1 ~ } \leq x _ { i } \leq m$ ) — the lengths of the passes available.

# Interaction

First, you should print a line containing either the string Alessia or the string Bernardo — the character that you want to impersonate.

Then, for each of the $n$ turns:

• If you are taking the role of Alessia, print a single line consisting of two integers $y$ and $a$ ( $1 \leq a \leq m - y + 1 )$ — you are choosing a pass of length $y$ and the interval of sections $[ a , a + y - 1 ]$ . Note that at least one pass of length $y$ must still be available. After this, read a single integer $b$ $a \leq b \leq a + y - 1 ,$ ) — the subject of the book selected by Bernardo.

• If you are taking the role of Bernardo, read two integers $y$ and $a$ ( $1 \leq a \leq m - y + 1$ ) — the length of the pass chosen by Alessia and the index of the first section of the interval. It is guaranteed that there is at least one pass of length $y$ available. Then, print a line consisting of a single integer $b$ $a \leq b \leq a + y - 1 _ { \mathit { \cdot } }$ ) — the subject from which you choose to take a book.

If one of your interactions is malformed, the interactor terminates immediately and your program receives the verdict WRONG-ANSWER. Otherwise, you will receive the verdict according to the game’s criteria described above.

After printing a line do not forget to end the line and flush the output. Otherwise, you will get the verdict TIMELIMIT. To flush the output, use:

• fflush(stdout) in C;   
• fflush(stdout), cout << flush or cout.flush() in $\mathrm { C } + +$ ;   
• System.out.flush() in Java and Kotlin;   
• sys.stdout.flush() in Python.

# Samples

<table><tr><td>Sample input 1</td><td>Sample output 1</td></tr><tr><td>514 372310</td><td></td></tr></table>

# Explanation of sample 1.

It can be shown that Alessia can accomplish her goal. An example of interaction (after reading the input) follows:

<table><tr><td rowspan=1 colspan=1>Contestant</td><td rowspan=1 colspan=1>Judge</td><td rowspan=1 colspan=1>Explanation</td></tr><tr><td rowspan=1 colspan=1>Alessia</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>The program will act as Alessia</td></tr><tr><td rowspan=1 colspan=1>311</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Choose y = 3 and a = 11</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>13</td><td rowspan=1 colspan=1>Judge selects b= 13</td></tr><tr><td rowspan=1 colspan=1>102</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Choose y = 10 and a= 2</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>9</td><td rowspan=1 colspan=1>Judge selects b = 9</td></tr><tr><td rowspan=1 colspan=1>71</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Choose y= 7 and a = 1</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>4</td><td rowspan=1 colspan=1>Judge selects b = 4</td></tr><tr><td rowspan=1 colspan=1>210</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Choose y = 2 and a = 10</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>10</td><td rowspan=1 colspan=1>Judge selects b = 10</td></tr><tr><td rowspan=1 colspan=1>36</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Choose y= 3 and a = 6</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>7</td><td rowspan=1 colspan=1>Judge selects b = 7</td></tr></table>

The program of the contestant wins because all the books chosen by Bernardo pertain to different topics. The actions performed by the contestant and the judge in this example of interaction may be non-optimal.

<table><tr><td>Sample input 2</td><td>Sample output 2</td></tr><tr><td>410</td><td></td></tr><tr><td></td><td></td></tr><tr><td>4164</td><td></td></tr></table>

# Explanation of sample 2.

It can be shown that Bernardo can manage to fulfil his goal. An example of interaction (after reading the input) follows:

<table><tr><td rowspan=1 colspan=1>Contestant</td><td rowspan=1 colspan=1>Judge</td><td rowspan=1 colspan=1>Explanation</td></tr><tr><td rowspan=1 colspan=1>Bernardo</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>The program will act as Bernardo</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>41</td><td rowspan=1 colspan=1>Judge chooses y = 4 and a = 1</td></tr><tr><td rowspan=1 colspan=1>4</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Select b= 4</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>110</td><td rowspan=1 colspan=1>Judge chooses y = 1 and a = 10</td></tr><tr><td rowspan=1 colspan=1>10</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Select b=10</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>63</td><td rowspan=1 colspan=1>Judge chooses y = 6 and a = 3</td></tr><tr><td rowspan=1 colspan=1>4</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Select b=4</td></tr><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>45</td><td rowspan=1 colspan=1>Judge chooses y = 4 and a = 5</td></tr><tr><td rowspan=1 colspan=1>8</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>Select b = 8</td></tr></table>

The program of the contestant wins because Bernardo has selected two books on topic number 4. The actions performed by the contestant and the judge in this example of interaction may be non-optimal.

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;

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 Gap {
    int L, R;
    int len() const { return R - L + 1; }
};




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

    
    int n = inf.readInt();
    int m = inf.readInt();
    vector<int> x(n);
    map<int, int> available_passes;
    for (int i = 0; i < n; ++i) {
        x[i] = inf.readInt();
        available_passes[x[i]]++;
    }

    
    query_limit = n;

    
    
    cout << n << " " << m << endl;
    for (int i = 0; i < n; ++i) {
        cout << x[i] << (i == n - 1 ? "" : " ");
    }
    cout << endl; 

    
    string role;
    if (!(cin >> role)) {
        finish(_wa, "Failed to read role");
    }
    
    
    string role_lower = role;
    transform(role_lower.begin(), role_lower.end(), role_lower.begin(), ::tolower);

    bool contestant_is_alessia = false;
    if (role_lower == "alessia") {
        contestant_is_alessia = true;
    } else if (role_lower == "bernardo") {
        contestant_is_alessia = false;
    } else {
        finish(_wa, "Invalid role: " + role);
    }

    
    vector<bool> topic_used(m + 1, false);
    
    
    
    vector<int> sorted_passes = x;
    sort(sorted_passes.rbegin(), sorted_passes.rend());
    vector<Gap> gaps;
    gaps.push_back({1, m});

    
    for (int turn = 0; turn < n; ++turn) {
        queries = turn + 1;
        
        
        if (turn % 10 == 0) log_metrics();

        if (contestant_is_alessia) {
            
            
            
            int y, a;
            if (!(cin >> y >> a)) {
                finish(_wa, "Failed to read move (y a) on turn " + to_string(turn + 1));
            }

            
            if (available_passes.find(y) == available_passes.end() || available_passes[y] <= 0) {
                finish(_wa, "Pass length " + to_string(y) + " not available or invalid");
            }
            available_passes[y]--;

            if (a < 1 || a + y - 1 > m) {
                finish(_wa, "Interval [" + to_string(a) + ", " + to_string(a + y - 1) + 
                            "] out of bounds [1, " + to_string(m) + "]");
            }

            
            
            
            int chosen_b = -1;
            for (int k = a; k < a + y; ++k) {
                if (topic_used[k]) {
                    chosen_b = k;
                    break;
                }
            }
            if (chosen_b == -1) {
                chosen_b = a; 
            }

            topic_used[chosen_b] = true;
            cout << chosen_b << endl; 

        } else {
            
            
            
            
            int y = sorted_passes[turn];
            
            
            
            
            
            int best_gap_idx = -1;
            int min_len = m + 2; 

            for (int i = 0; i < (int)gaps.size(); ++i) {
                if (gaps[i].len() >= y) {
                    if (gaps[i].len() < min_len) {
                        min_len = gaps[i].len();
                        best_gap_idx = i;
                    }
                }
            }

            int a;
            if (best_gap_idx != -1) {
                
                a = gaps[best_gap_idx].L;
            } else {
                
                
                a = 1;
            }

            cout << y << " " << a << endl; 

            int b;
            if (!(cin >> b)) {
                finish(_wa, "Failed to read response b on turn " + to_string(turn + 1));
            }

            
            if (b < a || b > a + y - 1) {
                finish(_wa, "Response b=" + to_string(b) + " not in interval [" + 
                            to_string(a) + ", " + to_string(a + y - 1) + "]");
            }

            topic_used[b] = true;

            
            gaps.clear();
            int current_L = -1;
            for (int i = 1; i <= m; ++i) {
                if (!topic_used[i]) {
                    if (current_L == -1) current_L = i;
                } else {
                    if (current_L != -1) {
                        gaps.push_back({current_L, i - 1});
                        current_L = -1;
                    }
                }
            }
            if (current_L != -1) {
                gaps.push_back({current_L, m});
            }
        }
    }

    
    int distinct_books = 0;
    for (int i = 1; i <= m; ++i) {
        if (topic_used[i]) distinct_books++;
    }

    bool alessia_won = (distinct_books == n);
    bool bernardo_won = !alessia_won;

    if (contestant_is_alessia) {
        if (alessia_won) {
            finish(_ok, "Contestant (Alessia) won: all topics distinct");
        } else {
            finish(_wa, "Contestant (Alessia) lost: duplicates found");
        }
    } else {
        if (bernardo_won) {
            finish(_ok, "Contestant (Bernardo) won: duplicate topics found");
        } else {
            finish(_wa, "Contestant (Bernardo) lost: all topics distinct");
        }
    }

    return 0;
}


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




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




int n, m;
multiset<int> available_passes;
set<int> used_books; 




void run_judge_bernardo() {
    for (int turn = 0; turn < n; turn++) {
        
        int y;
        if (!(cin >> y)) finish(_wa, "Unexpected end of input (reading y)");
        int a;
        if (!(cin >> a)) finish(_wa, "Unexpected end of input (reading a)");
        
        queries++;
        log_metrics(); 

        
        auto it = available_passes.find(y);
        if (it == available_passes.end()) {
            finish(_wa, format("Contestant used pass length %d which is not available", y));
        }
        available_passes.erase(it);

        if (a < 1 || a > m - y + 1) {
            finish(_wa, format("Contestant interval start %d is invalid for length %d with m=%d", a, y, m));
        }

        
        
        
        int choice = -1;
        for (int book : used_books) {
            if (book >= a && book <= a + y - 1) {
                choice = book;
                break;
            }
        }
        
        if (choice == -1) {
            choice = a; 
        }
        
        
        cout << choice << endl;
        used_books.insert(choice);
    }
    
    
    
    if (used_books.size() < n) {
        
        finish(_wa, "Bernardo (Judge) collected duplicates. Alessia (Contestant) lost.");
    } else {
        
        finish(_ok, "Bernardo (Judge) collected n distinct books. Alessia (Contestant) won.");
    }
}




void run_judge_alessia() {
    
    vector<int> passes(available_passes.begin(), available_passes.end());
    sort(passes.rbegin(), passes.rend());

    for (int turn = 0; turn < n; turn++) {
        int y = passes[turn];
        
        
        
        
        int chosen_a = -1;
        
        for (int a = 1; a <= m - y + 1; a++) {
            bool conflict = false;
            
            auto it = used_books.lower_bound(a);
            if (it != used_books.end() && *it <= a + y - 1) {
                conflict = true;
            }
            
            if (!conflict) {
                chosen_a = a;
                break;
            }
        }
        
        if (chosen_a == -1) {
            
            chosen_a = 1; 
        }
        
        
        cout << y << " " << chosen_a << endl;
        
        
        int b;
        if (!(cin >> b)) finish(_wa, "Unexpected end of input (reading b)");
        
        queries++;
        log_metrics();

        
        if (b < chosen_a || b > chosen_a + y - 1) {
            finish(_wa, format("Contestant chosen book %d is outside interval [%d, %d]", b, chosen_a, chosen_a + y - 1));
        }
        
        used_books.insert(b);
    }
    
    
    if (used_books.size() < n) {
        
        finish(_ok, "Bernardo (Contestant) managed to find duplicates. Won.");
    } else {
        
        finish(_wa, "Bernardo (Contestant) failed to find duplicates. Lost.");
    }
}

int main(int argc, char* argv[]) {
    
    registerInteraction(argc, argv);
    atexit(log_metrics); 
    
    
    n = inf.readInt(1, 100, "n");
    m = inf.readInt(n, 5000, "m");
    vector<int> x = inf.readInts(n, 1, m, "x");
    for (int val : x) available_passes.insert(val);
    
    
    query_limit = n;
    log_metrics();
    
    
    cout << n << " " << m << endl;
    for (int i = 0; i < n; i++) {
        cout << x[i] << (i == n - 1 ? "" : " ");
    }
    cout << endl; 
    
    
    string role;
    if (!(cin >> role)) finish(_wa, "Failed to read role");
    
    
    if (role == "Alessia") {
        run_judge_bernardo();
    } else if (role == "Bernardo") {
        run_judge_alessia();
    } else {
        finish(_wa, "Invalid role '" + role + "'. Expected 'Alessia' or 'Bernardo'.");
    }
    
    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 seed_val = -1;
    if (argc > 1) {
        try {
            seed_val = stoll(argv[1]);
        } catch (...) {
            seed_val = -1;
        }
    }

    
    int n, m;
    vector<int> x;

    
    if (seed_val == 1) {
        cout << "5 14" << endl;
        cout << "3 7 2 3 10" << endl;
        return 0;
    }
    
    if (seed_val == 2) {
        cout << "4 10" << endl;
        cout << "4 1 6 4" << endl;
        return 0;
    }

    
    if (seed_val == 3) {
        
        n = 100;
        m = 5000;
        x.assign(n, m);
    } else if (seed_val == 4) {
        
        n = 100;
        m = 5000;
        x.assign(n, 1);
    } else if (seed_val == 5) {
        
        n = 100;
        m = 100;
        x.assign(n, 1);
    } else {
        
        int min_n = 1, max_n = 100;
        int max_m = 5000;

        
        if (rnd.next(10) == 0) {
            max_n = 10;
            max_m = 50;
        }

        n = rnd.next(min_n, max_n);

        
        
        
        
        int m_strat = rnd.next(3);
        int upper_bound_m = max_m;
        
        if (m_strat == 0) {
            upper_bound_m = min((long long)max_m, (long long)n * 2);
        } else if (m_strat == 1) {
            upper_bound_m = min((long long)max_m, (long long)n * 10);
        }
        
        
        m = rnd.next(n, upper_bound_m);

        
        x.resize(n);
        for (int i = 0; i < n; i++) {
            
            
            
            
            int x_strat = rnd.next(10);
            if (x_strat < 3) {
                int limit = max(1, m / max(1, n));
                x[i] = rnd.next(1, limit);
            } else if (x_strat < 5) {
                int start = max(1, m / 2);
                x[i] = rnd.next(start, m);
            } else {
                x[i] = rnd.next(1, m);
            }
        }

        
        shuffle(x.begin(), x.end());
    }

    
    
    
    if (mode == "adp") {
        
    }

    
    println(n, m);
    println(x);

    return 0;
}