Problem: cf1673_f
Difficulty: medium
Categories: bit, math
Time limit: 2000 ms, memory limit: 256 MB

This is an interactive problem.

A city has $n^2$ buildings divided into a grid of $n$ rows and $n$ columns. You need to build a road of some length $D(A,B)$ of your choice between each pair of adjacent by side buildings $A$ and $B$. Due to budget limitations and legal restrictions, the length of each road must be a positive integer and the total length of all roads should not exceed $48\,000$.

There is a thief in the city who will start from the topmost, leftmost building (in the first row and the first column) and roam around the city, occasionally stealing artifacts from some of the buildings. He can move from one building to another adjacent building by travelling through the road which connects them.

You are unable to track down what buildings he visits and what path he follows to reach them. But there is one tracking mechanism in the city. The tracker is capable of storing a single integer $x$ which is initially $0$. Each time the thief travels from a building $A$ to another adjacent building $B$ through a road of length $D(A,B)$, the tracker changes $x$ to $x\oplus D(A,B)$. Each time the thief steals from a building, the tracker reports the value $x$ stored in it and resets it back to $0$.

It is known beforehand that the thief will steal in exactly $k$ buildings but you will know the values returned by the tracker only after the thefts actually happen. Your task is to choose the lengths of roads in such a way that no matter what strategy or routes the thief follows, you will be able to exactly tell the location of all the buildings where the thefts occurred from the values returned by the tracker.

Interaction

First read a single line containing two integers $n$ $(2\leq n\leq 32)$ and $k$ $(1\leq k\leq 1024)$ denoting the number of rows and number of thefts respectively.

Let's denote the $j$-th building in the $i$-th row by $B_{i,j}$.

Then print $n$ lines each containing $n-1$ integers. The $j$-th integer of the $i$-th line must be the value of $D(B_{i,j},B_{i,j+1})$.

Then print $n-1$ lines each containing $n$ integers. The $j$-th integer of the $i$-th line must be the value of $D(B_{i,j},B_{i+1,j})$.

Remember that the total length of the roads must not exceed $48\,000$.

Then answer $k$ queries. First read the value $x$ returned by the tracker. Then print two integers denoting the row number and column number of the building where the theft occurred. After that you will be able to answer the next query (if such exists).

After printing the answers do not forget to output end of line and flush the output buffer. Otherwise you will get the verdict Idleness limit exceeded. To flush the buffer, use:

* fflush(stdout) or cout.flush() in C++;
* System.out.flush() in Java;
* flush(output) in Pascal;
* stdout.flush() in Python;
* Read documentation for other languages.

Example

Input

```
2 4

14

1

14

3
```

Output

```
1
8
2 4

1 2

1 1

1 2

2 1
```

Note

For the sample test, $n=2$ and $k=4$.

You choose to build the roads of the following lengths:

 ![](https://espresso.codeforces.com/ecceb8e844d103a4c2df2d68233ebcb8b1f45d70.png) 

The thief follows the following strategy:

1. Start at $B_{1,1}$.
2. Move Right to $B_{1,2}$.
3. Move Down to $B_{2,2}$.
4. Move Left to $B_{2,1}$.
5. Move Up to $B_{1,1}$.
6. Move Right to $B_{1,2}$.
7. Steal from $B_{1,2}$.
8. Move Left to $B_{1,1}$.
9. Steal from $B_{1,1}$.
10. Move Down to $B_{2,1}$.
11. Move Right to $B_{2,2}$.
12. Move Up to $B_{1,2}$.
13. Steal from $B_{1,2}$.
14. Move Left to $B_{1,1}$.
15. Move Down to $B_{2,1}$.
16. Steal from $B_{2,1}$.

The tracker responds in the following way:

1. Initialize $x=0$.
2. Change $x$ to $x\oplus 1=0\oplus1=1$.
3. Change $x$ to $x\oplus 4=1\oplus4=5$.
4. Change $x$ to $x\oplus 8=5\oplus8=13$.
5. Change $x$ to $x\oplus 2=13\oplus2=15$.
6. Change $x$ to $x\oplus 1=15\oplus1=14$.
7. Return $x=14$ and re-initialize $x=0$.
8. Change $x$ to $x\oplus 1=0\oplus1=1$.
9. Return $x=1$ and re-initialize $x=0$.
10. Change $x$ to $x\oplus 2=0\oplus2=2$.
11. Change $x$ to $x\oplus 8=2\oplus8=10$.
12. Change $x$ to $x\oplus 4=10\oplus4=14$.
13. Return $x=14$ and re-initialize $x=0$.
14. Change $x$ to $x\oplus 1=0\oplus1=1$.
15. Change $x$ to $x\oplus 2=1\oplus2=3$.
16. Return $x=3$ and re-initialize $x=0$.

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

using namespace std;


static int queries = 0;
static int 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 h_weight[35][35];
int v_weight[35][35];

int N, K;


string readTokenRobust() {
    string s;
    if (!(cin >> s)) {
        finish(_pe, "Unexpected end of output from contestant.");
    }
    if (s == "!") {
        if (!(cin >> s)) finish(_pe, "Unexpected end of output after '!'.");
    }
    return s;
}


int readIntRobust() {
    string s = readTokenRobust();
    try {
        size_t idx;
        int val = stoi(s, &idx);
        if (idx != s.length()) finish(_pe, "Expected integer, found garbage: " + s);
        return val;
    } catch (...) {
        finish(_pe, "Expected integer, found: " + s);
    }
    return 0;
}




int get_xor_path(int r1, int c1, int r2, int c2) {
    if (r1 == r2 && c1 == c2) return 0;

    static int dist[35][35];
    static bool visited[35][35];

    
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= N; ++j) {
            visited[i][j] = false;
            dist[i][j] = 0;
        }
    }

    queue<pair<int, int>> q;
    q.push({r1, c1});
    visited[r1][c1] = true;
    dist[r1][c1] = 0;

    while (!q.empty()) {
        auto [r, c] = q.front();
        q.pop();

        if (r == r2 && c == c2) return dist[r][c];

        

        
        if (c + 1 <= N && !visited[r][c+1]) {
            visited[r][c+1] = true;
            dist[r][c+1] = dist[r][c] ^ h_weight[r][c];
            q.push({r, c+1});
        }
        
        if (c - 1 >= 1 && !visited[r][c-1]) {
            visited[r][c-1] = true;
            dist[r][c-1] = dist[r][c] ^ h_weight[r][c-1];
            q.push({r, c-1});
        }
        
        if (r + 1 <= N && !visited[r+1][c]) {
            visited[r+1][c] = true;
            dist[r+1][c] = dist[r][c] ^ v_weight[r][c];
            q.push({r+1, c});
        }
        
        if (r - 1 >= 1 && !visited[r-1][c]) {
            visited[r-1][c] = true;
            dist[r-1][c] = dist[r][c] ^ v_weight[r-1][c];
            q.push({r-1, c});
        }
    }
    return 0; 
}

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

    
    N = inf.readInt();
    K = inf.readInt();
    query_limit = K;

    vector<pair<int, int>> targets;
    targets.reserve(K);
    for (int i = 0; i < K; ++i) {
        targets.emplace_back(inf.readInt(), inf.readInt());
    }

    
    cout << N << " " << K << endl;

    
    long long total_cost = 0;

    
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j < N; ++j) {
            int w = readIntRobust();
            if (w <= 0) finish(_wa, "Weights must be positive integers.");
            h_weight[i][j] = w;
            total_cost += w;
        }
    }

    
    for (int i = 1; i < N; ++i) {
        for (int j = 1; j <= N; ++j) {
            int w = readIntRobust();
            if (w <= 0) finish(_wa, "Weights must be positive integers.");
            v_weight[i][j] = w;
            total_cost += w;
        }
    }

    if (total_cost > 48000) {
        finish(_wa, "Total weight " + to_string(total_cost) + " exceeds limit 48000.");
    }

    
    int cur_r = 1, cur_c = 1;
    log_metrics(); 

    for (int i = 0; i < K; ++i) {
        int target_r = targets[i].first;
        int target_c = targets[i].second;

        
        int x = get_xor_path(cur_r, cur_c, target_r, target_c);

        
        cout << x << endl;

        
        int r = readIntRobust();
        int c = readIntRobust();

        if (r != target_r || c != target_c) {
            finish(_wa, format("Query %d: Expected (%d, %d), found (%d, %d).", i + 1, target_r, target_c, r, c));
        }

        
        queries++;
        log_metrics();
        cur_r = target_r;
        cur_c = target_c;
    }

    finish(_ok, format("Passed %d queries.", K));
}


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

using namespace std;





static int queries = 0;
static int query_limit = 0;


static void log_metrics() {
    if (query_limit == 0) return; 
    try {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}


static void finish(TResult verdict, const char* fmt, ...) {
    log_metrics();
    
    va_list args;
    va_start(args, fmt);
    char buffer[4096];
    vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);
    
    quitf(verdict, "%s", buffer);
}





struct Edge {
    int to;
    int weight;
};

int N, K;
vector<pair<int, int>> targets;


vector<vector<Edge>> adj;
long long total_weight = 0;


vector<int> P;
vector<bool> visited;

vector<vector<int>> collisions;





void validate_and_read_grid() {
    
    
    for (int r = 0; r < N; r++) {
        for (int c = 0; c < N - 1; c++) {
            int w;
            cin >> w;
            if (cin.fail()) finish(_pe, "Failed to read horizontal edge weight");
            if (w < 1) finish(_wa, "Edge weights must be positive");
            total_weight += w;
            
            int u = r * N + c;
            int v = r * N + (c + 1);
            adj[u].push_back({v, w});
            adj[v].push_back({u, w});
        }
    }

    
    
    for (int r = 0; r < N - 1; r++) {
        for (int c = 0; c < N; c++) {
            int w;
            cin >> w;
            if (cin.fail()) finish(_pe, "Failed to read vertical edge weight");
            if (w < 1) finish(_wa, "Edge weights must be positive");
            total_weight += w;
            
            int u = r * N + c;
            int v = (r + 1) * N + c;
            adj[u].push_back({v, w});
            adj[v].push_back({u, w});
        }
    }

    if (total_weight > 48000) {
        finish(_wa, "Total weight exceeds 48000");
    }
}

void analyze_graph() {
    P.assign(N * N, -1);
    visited.assign(N * N, false);
    
    
    queue<int> q;
    q.push(0);
    P[0] = 0;
    visited[0] = true;

    while(!q.empty()) {
        int u = q.front();
        q.pop();

        for (auto& e : adj[u]) {
            if (!visited[e.to]) {
                visited[e.to] = true;
                P[e.to] = P[u] ^ e.weight;
                q.push(e.to);
            }
        }
    }

    
    for (int u = 0; u < N * N; u++) {
        if (!visited[u]) {
            finish(_wa, "Graph is not connected");
        }
    }

    
    map<int, vector<int>> pot_map;
    for (int u = 0; u < N * N; u++) {
        pot_map[P[u]].push_back(u);
    }

    for (auto const& [val, nodes] : pot_map) {
        if (nodes.size() > 1) {
            collisions.push_back(nodes);
        }
    }
}

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

    
    N = inf.readInt();
    K = inf.readInt();
    
    
    query_limit = K;
    log_metrics();

    
    for (int i = 0; i < K; i++) {
        int r = inf.readInt();
        int c = inf.readInt();
        targets.push_back({r - 1, c - 1}); 
    }

    
    cout << N << " " << K << endl;

    
    adj.resize(N * N);
    validate_and_read_grid();

    
    analyze_graph();

    
    int current_node = 0; 

    for (int i = 0; i < K; i++) {
        queries++;
        log_metrics(); 

        int target_node = -1;
        int reported_xor = -1;
        
        bool using_bad_edge = false;
        bool using_collision = false;
        vector<int> current_collision_set;

        
        
        
        
        for (auto& e : adj[current_node]) {
            if ((P[current_node] ^ P[e.to]) != e.weight) {
                target_node = e.to;
                reported_xor = e.weight;
                using_bad_edge = true;
                break;
            }
        }

        
        
        
        if (!using_bad_edge && !collisions.empty()) {
            
            const auto& col_set = collisions[i % collisions.size()];
            current_collision_set = col_set;
            using_collision = true;
            
            
            target_node = col_set[0];
            
            if (target_node == current_node && col_set.size() > 1) {
                target_node = col_set[1];
            }
            
            reported_xor = P[current_node] ^ P[target_node];
        }

        
        if (!using_bad_edge && !using_collision) {
            pair<int, int> t = targets[i];
            target_node = t.first * N + t.second;
            reported_xor = P[current_node] ^ P[target_node];
        }

        
        cout << reported_xor << endl;

        
        int r, c;
        cin >> r >> c;
        if (cin.fail()) finish(_pe, "Failed to read response coordinates");
        
        if (r < 1 || r > N || c < 1 || c > N) {
            finish(_wa, "Response coordinates out of bounds: %d %d", r, c);
        }
        
        int guessed_node = (r - 1) * N + (c - 1);

        
        if (using_bad_edge) {
            
            
            
            if (guessed_node != target_node) {
                finish(_wa, "Wrong location (inconsistent cycle exploited)");
            }
            
            
            current_node = target_node;
        } 
        else if (using_collision) {
            
            if (P[guessed_node] != P[target_node]) {
                finish(_wa, "Wrong location (potential mismatch)");
            }
            
            
            
            bool found_adversarial = false;
            for (int candidate : current_collision_set) {
                if (candidate != guessed_node) {
                    
                    finish(_wa, "Wrong location (ambiguous potentials exploited)");
                }
            }
            
            
            current_node = target_node;
        } 
        else {
            
            if (guessed_node != target_node) {
                finish(_wa, "Wrong location. Expected (%d, %d), found (%d, %d)", 
                       target_node / N + 1, target_node % N + 1, r, c);
            }
            current_node = target_node;
        }
    }

    finish(_ok, "Correct");
    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");
    
    int n = opt<int>("n", -1);
    int k = opt<int>("k", -1);
    
    
    long long seed_val = atoll(argv[1]);

    
    if (n == -1) {
        if (seed_val == 1) n = 2;       
        else if (seed_val == 2) n = 32; 
        else if (seed_val == 3) n = 32; 
        else {
            
            int t = rnd.next(100);
            if (t < 5) n = 2;
            else if (t < 15) n = rnd.next(3, 10);
            else if (t < 45) n = rnd.next(11, 30);
            else n = 32;
        }
    }

    
    if (k == -1) {
        if (seed_val == 1) k = 1;       
        else if (seed_val == 2) k = 1024; 
        else if (seed_val == 3) k = 1024;
        else {
            
            int t = rnd.next(100);
            if (t < 5) k = 1;
            else if (t < 15) k = rnd.next(2, 20);
            else if (t < 45) k = rnd.next(21, 500);
            else k = rnd.next(501, 1024);
        }
    }

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

    
    
    
    

    if (seed_val == 1 && n == 2 && k == 1) {
        
        cout << "2 2" << endl;
    } else {
        
        for (int i = 0; i < k; ++i) {
            cout << rnd.next(1, n) << " " << rnd.next(1, n) << "\n";
        }
    }

    return 0;
}