Problem: cf2052_h
Difficulty: medium
Categories: search
Time limit: 6000 ms, memory limit: 1024 MB

This is an interactive problem.
Harry and Hermione are trying to hunt down hoglins which are haunting Hogwarts. There is a long hallway in Hogwarts, consisting of  $n$  individual cells, numbered from 1 to  $n$  from the left to the right.
Hermione can cast a spell that would block any cell of the hallway of her choosing. After the spell is cast, the blocked cell will remain blocked while she casts other spells.
Hoglins are simple creatures; all they do is randomly move around and bump into stuff. To be more precise, every hoglin has a range which it considers to be accessible. Initially, when the hoglin appears, it is a range from the cell 1 to the cell  $n$ .
Initially, a single hoglin appears in a cell of the hallway chosen uniformly at random. Then, until this hoglin is caught, the following happens on every round of the hunt:
- Hermione can cast a spell to block any single cell of her choosing, or do nothing.
- If the cell she is trying to block is the cell with a hoglin in it, the hoglin is caught. After that, all the blocked cells become free again, and, if there are more hoglins to be caught, a new hoglin immediately appears in a random location, and the hunt begins again.
- Otherwise, the hoglin chooses a cell uniformly at random from its accessible range and tries to move to that cell, moving one cell at a time towards a chosen cell. Regardless of the distance, all the steps of the movement, as described below, happen in the same round.
- If the chosen cell is to the right of the hoglin, it moves to the right; if the chosen cell is to the left of the hoglin, it moves to the left. If the chosen cell is the same as where the hoglin is now, it does nothing.
- If at any point during the movement towards the chosen cell a hoglin is trying to move to the right or to the left from an unblocked cell at position  $i$  to the neighbouring blocked cell at position  $i \pm 1$ , the hoglin updates the right or left boundary of its accessible range correspondingly to be  $i$ .
- If on the way to the chosen cell, the hoglin tries to move to a blocked cell, Harry and Hermione hear a loud sound, as the hoglin bumps into the blocked cell. In this case, the hoglin returns to the position it has originally started from at the beginning of this round.
- Otherwise, if the hoglin does not bump into any blocked cells on its way, it does not change its accessible range and stays at the new position. In that case, Harry and Hermione hear nothing.
To free Hogwarts from hoglins, Harry and Hermione should catch  $k$  of them, but they don't have much time. They can only afford to hunt hoglins for at most 200 000 rounds. Please help them find an efficient strategy to do that.
# Interaction Protocol
First, the testing system will write two integers  $n$  and  $k$  ( $1 \leq n \leq 10^{18}$ ;  $1 \leq k \leq 800$ ) — the number of cells in Hogwarts' hallway and the number of hoglins that should be caught. Then the catching process begins.
The following interaction proceeds in rounds as described in the problem statement.
At the start of each round, your program should output Hermione's action — an integer  $p$  ( $0 \leq p \leq n$ ) representing the position of the cell Hermione is going to block. If  $p = 0$  or the cell at position  $p$  is already blocked, she does nothing in this round.
Then, if the current position of the hoglin is at the newly blocked cell  $p$ , the hoglin is caught; the testing system outputs 2, all the blocked cells become free, and interaction rounds start again. In case you caught the  $k$ -th hoglin, the testing system outputs 3 instead of 2, and your program should immediately stop execution.
Otherwise, the hoglin attempts to move according to the rules described in the problem statement. If in the process it bumps into any blocked cell, the testing system outputs 1; otherwise, it outputs 0.
If your 200 000-th action does not catch the  $k$ -th hoglin, the testing system outputs -1 instead of its usual answer, and your program should immediately stop execution to guarantee the "Wrong Answer" verdict.
The interactor in this problem is not adaptive. It is guaranteed that the hoglins follow the rules described in the problem statement. The starting cell for each hoglin is chosen uniformly at random and their moves are chosen uniformly at random from the range of cells that they consider accessible.
The problem has at most 15 tests.
Here is the summary of all possible interactor answers:
- -1 — too many actions;
- 0 - hoglin moved successfully, did not bump;
- 1 - hoglin attempted to move, bumped into blocked cell;
- 2 - hoglin is caught, interaction starts again;
- 3 - hoglin is caught, stop.

Example

<table><tr><td>standard input</td><td>standard output</td><td>Illustration</td></tr><tr><td>9 2</td><td></td><td>1 2 3 4 5 6 7 8 9</td></tr><tr><td>0</td><td>3</td><td>start at 8block 3move to 4, successblock 7move to 9, bumpedblock 5move to 3, bumpedblock 1move to 4, successblock 9move to 5, bumpedblock 4, caught</td></tr><tr><td>1</td><td>7</td><td></td></tr><tr><td>1</td><td>5</td><td></td></tr><tr><td>1</td><td>1</td><td></td></tr><tr><td>0</td><td>9</td><td></td></tr><tr><td>1</td><td>4</td><td></td></tr><tr><td>2</td><td>5</td><td></td></tr><tr><td>1</td><td>7</td><td></td></tr><tr><td>0</td><td>0</td><td></td></tr><tr><td>0</td><td>2</td><td></td></tr><tr><td>3</td><td></td><td></td></tr></table>
# Note
We show the sample from the point of view of the hoglins.
The black dot shows the current position of the hoglin.
Crosses mark blocked cells.
White cells mark the range which the hoglin considers to be accessible; other cells are marked gray.
On the right is the action that was performed by either Hermione or the hoglin to get to this state from the previous one.

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

using namespace std;



static long long queries = 0;
static long long query_limit = 200000;


static long long n;
static int k;
static long long seed_val;
static int caught_count = 0;

static long long cur_pos;
static long long range_L, range_R;
static set<long long> blocked;




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


void spawn_hoglin() {
    
    cur_pos = rnd.next(1LL, n);
    
    range_L = 1;
    range_R = n;
    
    blocked.clear();
}

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

    
    n = inf.readLong();
    k = inf.readInt();
    
    
    if (!inf.seekEof()) {
        seed_val = inf.readLong();
    } else {
        seed_val = 847204852305LL; 
    }
    
    
    rnd.setSeed(seed_val);

    
    cout << n << " " << k << endl;

    
    spawn_hoglin();

    while (true) {
        
        
        
        if (queries > query_limit + 10) {
            finish(_pe, "Hard query limit exceeded (safety cap)");
        }

        
        string token;
        if (!(cin >> token)) {
            finish(_pe, "Unexpected end of file from contestant");
        }

        long long p = -1;
        
        if (token == "!") {
            finish(_pe, "Protocol violation: unexpected '!' token");
        } else if (token == "?") {
            if (!(cin >> p)) finish(_pe, "Expected integer after '?'");
        } else {
            try {
                p = stoll(token);
            } catch (...) {
                finish(_pe, "Invalid integer format");
            }
        }

        
        if (p < 0 || p > n) {
            finish(_pe, format("Position %lld out of range [0, %lld]", p, n));
        }

        queries++;
        
        
        
        bool newly_blocked = false;
        if (p != 0) {
            if (blocked.find(p) == blocked.end()) {
                blocked.insert(p);
                newly_blocked = true;
            }
        }

        
        
        
        if (newly_blocked && p == cur_pos) {
            caught_count++;
            if (caught_count == k) {
                cout << 3 << endl;
                finish(_ok, format("Caught %d hoglins in %lld queries", k, queries));
            } else {
                cout << 2 << endl;
                spawn_hoglin();
                continue; 
            }
        }

        
        
        
        if (queries >= query_limit) {
            cout << -1 << endl;
            finish(_wa, "Query limit exceeded without catching required hoglins");
        }

        
        
        long long target = rnd.next(range_L, range_R);

        if (target == cur_pos) {
            
            cout << 0 << endl;
        } else {
            bool bumped = false;
            long long collider = -1;
            
            if (target > cur_pos) {
                
                
                auto it = blocked.upper_bound(cur_pos);
                if (it != blocked.end() && *it <= target) {
                    bumped = true;
                    collider = *it;
                    
                    
                    
                    range_R = collider - 1;
                }
            } else {
                
                
                auto it = blocked.lower_bound(cur_pos);
                if (it != blocked.begin()) {
                    it--; 
                    if (*it >= target) {
                        bumped = true;
                        collider = *it;
                        
                        
                        
                        range_L = collider + 1;
                    }
                }
            }

            if (bumped) {
                
                cout << 1 << endl;
            } else {
                
                cur_pos = target;
                cout << 0 << endl;
            }
        }
    }

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

    long long n = 10;
    int k = 1;

    
    int seed_idx = 0;
    if (argc > 1) {
        string s = argv[1];
        if (!s.empty() && all_of(s.begin(), s.end(), ::isdigit)) {
            try {
                seed_idx = stoi(s);
            } catch (...) {
                seed_idx = 0;
            }
        }
    }

    
    if (n_opt != -1) {
        n = n_opt;
    } else {
        
        if (seed_idx == 1) {
            n = 1; 
        } else if (seed_idx == 2) {
            n = 1000000000000000000LL; 
        } else if (seed_idx == 3) {
            n = 10; 
        } else {
            
            int type = rnd.next(1, 100);
            if (type <= 10) { 
                
                n = rnd.next(1LL, 1000LL);
            } else if (type <= 70) {
                
                
                int e = rnd.next(3, 18);
                long long low = 1;
                for (int i = 0; i < e; ++i) low *= 10; 
                
                long long high;
                if (e >= 18) {
                    
                    
                    low = 100000000000000000LL; 
                    high = 1000000000000000000LL;
                } else {
                    high = low * 10 - 1;
                }
                
                if (high > 1000000000000000000LL) high = 1000000000000000000LL;
                if (low > high) low = high;
                
                n = rnd.next(low, high);
            } else {
                
                n = rnd.next(100000000000000000LL, 1000000000000000000LL);
                
                
                if (rnd.next(1, 10) == 1) {
                    int p = rnd.next(50, 60);
                    unsigned long long p2 = (1ULL << p);
                    if (p2 <= 1000000000000000000ULL) n = (long long)p2;
                }
            }
        }
    }

    
    if (k_opt != -1) {
        k = k_opt;
    } else {
        if (seed_idx == 1) {
            k = 1; 
        } else if (seed_idx == 2) {
            k = 800; 
        } else if (seed_idx == 3) {
            k = 800; 
        } else {
            
            int type = rnd.next(1, 100);
            if (type <= 5) k = 1;
            else if (type <= 10) k = 800;
            else if (type <= 40) k = rnd.next(1, 50); 
            else k = rnd.next(51, 800); 
        }
    }

    
    if (n < 1) n = 1;
    if (n > 1000000000000000000LL) n = 1000000000000000000LL;
    if (k < 1) k = 1;
    if (k > 800) k = 800;

    
    if (mode == "non") {
        
        
        long long interactor_seed = rnd.next(1LL, 1000000000000000000LL);
        cout << n << " " << k << " " << interactor_seed << endl;
    } else if (mode == "adp") {
        
        
        cout << n << " " << k << endl;
    } else {
        
        long long interactor_seed = rnd.next(1LL, 1000000000000000000LL);
        cout << n << " " << k << " " << interactor_seed << endl;
    }

    return 0;
}