Problem: icpc2022_asia_hangzhou_i
Difficulty: medium
Categories: graph, data structures, math
Time limit: 1000 ms, memory limit: 1024 MB

# This is an interactive problem.

Grammy has a directed cyclic graph of $n$ vertices ( $1 \leq n \leq 1 0 ^ { 9 }$ ) numbered from 1 to $n$ . A directed cyclic graph is a directed graph of $n$ vertices that form one cycle. Specifically, there are $n$ vertices and $n$ edges in the graph, and there exists a permutation $p _ { 1 } , p _ { 2 } , \ldots , p _ { n }$ such that there is a one-way edge from $p _ { i }$ to

$p ( i \mathrm { m o d } n ) { + } 1$

Initially, there is a token on a predetermined vertex.

You can ask Grammy to move the token in the following way:

“walk $\tt { x } ^ { \prime \prime }$ where $0 \leq x \leq 1 0 ^ { 9 }$ . In response to the query, Grammy will move the token through exactly edges and tell you the position of the token after moving.

You win if you guess the number of vertices in the hidden graph (number $n$ ) by making no more than $1 0 ^ { 4 }$ queries.

The vertices in the graph and the initial position of the token are fixed in advance.

# Interaction Protocol

You can make no more than $1 0 ^ { 4 }$ queries. To make a query, output “walk x” ( $0 \leq x \leq 1 0 ^ { 9 }$ ) on a separate line, then you should read the response from standard input.

In response to the query, the interactor will move the token through exactly $x$ edges and output the position of the token after moving.

To give your answer, print “guess n” on a separate line, where $n$ is the size of the hidden graph $1 \leq n \leq 1 0 ^ { 9 }$ ). The output of the answer is not counted towards the limit of $1 0 ^ { 4 }$ queries.

After that, your program should terminate.

After printing a query, do not forget to output end of line and flush the output. To do this, use fflush(stdout) or cout.flush() in $\mathrm { C } + +$ , System.out.flush() in Java, flush(output) in Pascal, or stdout.flush() in Python.

It is guaranteed that the vertices in the graph and the initial position of the token are fixed in advance.

# Example

<table><tr><td>standard input</td><td>standard output</td></tr><tr><td>3</td><td>walk 0</td></tr><tr><td></td><td>walk 1</td></tr><tr><td>10</td><td>walk 2</td></tr><tr><td>4</td><td>walk 3</td></tr><tr><td>5</td><td>walk 4</td></tr><tr><td>3</td><td></td></tr><tr><td>5</td><td>walk 6 guess 10</td></tr></table>

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

using namespace std;


static long long queries = 0;

static const long long query_limit = 10000;

static const long long hard_cap = 20000;



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 main(int argc, char* argv[]) {
    
    registerInteraction(argc, argv);
    atexit(log_metrics);

    
    
    long long n = inf.readLong();
    long long start_pos = inf.readLong();
    int label_type = inf.readInt();
    long long seed_val = inf.readLong();

    
    log_metrics();

    
    
    
    
    
    
    long long current_index = start_pos;
    vector<int> p;

    if (label_type == 1) {
        
        
        if (n <= 20000000) {
            p.resize(n);
            iota(p.begin(), p.end(), 1);
            
            mt19937_64 rng(seed_val);
            shuffle(p.begin(), p.end(), rng);
        } else {
            
            label_type = 0;
        }
    }

    
    while (true) {
        
        if (queries > hard_cap) {
            finish(_pe, "Hard query limit exceeded");
        }

        string token;
        
        if (!(cin >> token)) {
            
            finish(_wa, "Unexpected EOF (did not guess n)");
        }

        bool is_query = false;
        bool is_answer = false;
        long long val = -1;

        
        
        string lower_token = token;
        transform(lower_token.begin(), lower_token.end(), lower_token.begin(), ::tolower);

        if (lower_token == "walk" || token == "?") {
            is_query = true;
            if (!(cin >> val)) finish(_pe, "Expected number after walk/? token");
        } else if (lower_token == "guess" || token == "!") {
            is_answer = true;
            if (!(cin >> val)) finish(_pe, "Expected number after guess/! token");
        } else {
            
            try {
                size_t idx;
                val = stoll(token, &idx);
                if (idx != token.size()) {
                    
                    finish(_pe, ("Invalid token: " + token).c_str());
                }
                is_query = true;
            } catch (...) {
                finish(_pe, ("Invalid token: " + token).c_str());
            }
        }

        if (is_query) {
            if (val < 0) finish(_pe, "Walk distance must be non-negative");

            
            current_index = (current_index + val) % n;

            
            int label;
            if (label_type == 0) {
                
                label = (int)(current_index + 1);
            } else {
                
                label = p[current_index];
            }

            cout << label << endl;
            queries++;
            
            
            if (queries % 100 == 0) log_metrics();

        } else if (is_answer) {
            
            if (val == n) {
                finish(_ok, "Correct guess");
            } else {
                finish(_wa, "Wrong guess");
            }
        }
    }

    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 seed_val = rnd.next(1LL, 1000000000000000000LL);

    if (mode == "non") {
        long long n = -1;
        
        
        if (has_opt("n")) {
            n = opt<long long>("n");
        } else {
            
            int type = rnd.next(1, 100);
            
            if (type <= 5) {
                
                n = rnd.next(1, 10);
            } else if (type <= 10) {
                
                int p = rnd.next(1, 9);
                long long base = 1; 
                for(int k=0; k<p; k++) base *= 10;
                n = base + rnd.next(-2, 2);
                if (n < 1) n = 1;
            } else if (type <= 20) {
                
                n = 1000000000LL - rnd.next(0, 100);
            } else if (type <= 25) {
                
                n = 999999937;
            } else if (type <= 60) {
                
                n = rnd.next(1000000LL, 1000000000LL);
            } else {
                
                long long lower = 1;
                long long upper = 1000000000LL;
                
                long long log_range = rnd.next(0, 9);
                long long range_start = 1;
                for(int k=0; k<log_range; k++) range_start *= 10;
                long long range_end = range_start * 10 - 1;
                if (range_end > upper) range_end = upper;
                n = rnd.next(range_start, range_end);
            }
        }
        
        long long start_pos = rnd.next(0LL, n - 1);
        
        
        
        
        int label_type = 0;
        if (has_opt("type")) {
            label_type = opt<int>("type");
        } else {
            
            if (n <= 20000000) label_type = 1;
            else label_type = 0;
            
            
            if (rnd.next(1, 20) == 1) label_type = 1 - label_type;
        }

        
        cout << n << " " << start_pos << " " << label_type << " " << seed_val << endl;

    } else if (mode == "adp") {
        
        
        long long min_n = opt<long long>("min_n", 1);
        long long max_n = opt<long long>("max_n", 1000000000);
        int label_type = opt<int>("type", 0); 
        
        
        cout << min_n << " " << max_n << " " << label_type << " " << seed_val << endl;
    }

    return 0;
}