Problem: cf1934_d2
Difficulty: easy
Categories: game, bit, greedy
Time limit: 3000 ms, memory limit: 256 MB

This is an interactive problem.

This is the game version of the problem. Note that the solution of this problem may or may not share ideas with the solution of the solo version. You can solve and get points for both versions independently.

Alice and Bob are playing a game. The game starts with a positive integer $n$, with players taking turns. On each turn of the game, the following sequence of events takes place:

* The player having the integer $p$ breaks it into two integers $p_{1}$ and $p_{2}$, where $0 \lt p_{1} \lt p$, $0 \lt p_{2} \lt p$ and $p_{1} \oplus p_{2} = p$.
* If no such $p_{1}$, $p_{2}$ exist, the player loses.
* Otherwise, the opponent does either select the integer $p_{1}$ or $p_{2}$.
* The game continues with the selected integer. The opponent will try to break it.

As Alice, your goal is to win. You can execute a maximum of $63$ break operations. You have the choice to play first or second. The system will act for Bob.

Here $\oplus$ denotes the bitwise XOR operation.

Input

Each test contains multiple test cases. The first line of input contains a single integer $t$ ($1 \leq t \leq 1000$) — the number of test cases.

The only line of each test case contains a single integer $n$ ($1 \leq n \leq 10^{18}$) — the number the game starts with.

Interaction

For each test case, the interaction begins by reading the integer $n$.

After reading $n$, print a single line containing either "first" or "second", denoting what you want to play as (as first or second correspondingly).

On Alice's turn, you are required to print two positive integers, $p_{1}$ and $p_{2}$ such that $0 \lt p_{1} \lt p$, $0 \lt p_{2} \lt p$ and $p_{1} \oplus p_{2} = p$. Here, $p$ equals one of the two integers printed by Bob in the previous turn. If no turn has occurred previously, $p$ is equal to $n$. If Alice cannot perform a break operation, print "0 0" to receive a Wrong answer verdict.

On Bob's turn, you should read two integers, $p_{1}$ and $p_{2}$ such that $0 \lt p_{1} \lt p$, $0 \lt p_{2} \lt p$ and $p_{1} \oplus p_{2} = p$. Here, $p$ equals one of the two integers printed by Alice in the previous turn. If no turn has occurred previously, $p$ is equal to $n$. If Bob cannot perform a break operation $p_{1} = 0$ and $p_2 = 0$ in which case you should proceed to the next test case.

If any break operation performed by Alice is invalid, the interactor prints "-1 -1" and your code should promptly exit to receive a wrong answer verdict.

If Alice performs $63$ turns and Bob can still execute a break operation on the current integers, the interactor prints "-1 -1", and your code should promptly exit to receive a wrong answer verdict.

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

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

Example

Input

```
4
1

0 0
3

0 0
13

3 4

0 0
777777770001

0 0
```

Output

```
second

first
2 1

first
10 7

1 2

first
777777770000 1
```

Note

Explanation for the interaction.

|  |  |  |
| --- | --- | --- |
| Interactor / Bob | Alice | Explanation |
| 4 |  | $t$ |
| 1 |  | $n$ for the first test case |
|  | second | Alice chooses to go second |
| 0 0 |  | Bob says he cannot break $p = 1$ |
| 3 |  | $n$ for the second test case |
|  | first | Alice chooses to go first |
|  | 1 2 | Alice breaks $p = 3$ into $p_1 = 1$ and $p_2 = 2$ |
| 0 0 |  | Bob says he cannot break $p = 1$ or $p = 2$ |
| 13 |  | $n$ for the third test case |
|  | first | Alice chooses to go first |
|  | 10 7 | Alice breaks $p = 13$ into $p_1 = 10$ and $p_2 = 7$ |
| 3 4 |  | Bob breaks $p = 7$ into $p_1 = 3$ and $p_2 = 4$ |
|  | 1 2 | Alice breaks $p = 3$ into $p_1 = 1$ and $p_2 = 2$ |
| 0 0 |  | Bob says he cannot break $p = 1$ or $p = 2$ |
| 777777770001 |  | $n$ for the fourth test case |
|  | first | Alice chooses to go first |
|  | 777777770000 1 | Alice breaks $p = 777\,777\,770\,001$ into $p_1 = 777\,777\,770\,000$ and $p_2 = 1$ |
| 0 0 |  | Bob says he cannot perform break operation. |

This table is for explanation only and does not reflect the actual behavior of the interactor.

Note that in the last test case Bob could choose $p_1$ and perform a break operation but he gave up.

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

using i64 = long long;
using u64 = unsigned long long;

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

static bool isPowerOfTwo(u64 x) {
    return x && ((x & (x - 1ULL)) == 0ULL);
}

static bool canBreak(u64 p) {
    return !isPowerOfTwo(p);
}

static bool readToken(string& s) {
    return (cin >> s) ? true : false;
}

static bool parseI64(const string& s, i64& out) {
    if (s.empty()) return false;
    int i = 0;
    bool neg = false;
    if (s[0] == '-') {
        neg = true;
        i = 1;
        if ((int)s.size() == 1) return false;
    }
    for (; i < (int)s.size(); ++i) {
        if (s[i] < '0' || s[i] > '9') return false;
    }
    try {
        size_t idx = 0;
        long long v = stoll(s, &idx, 10);
        if (idx != s.size()) return false;
        out = v;
        return true;
    } catch (...) {
        return false;
    }
}

static pair<u64, u64> splitLowbit(u64 p) {
    u64 a = p & (~p + 1ULL); 
    u64 b = p ^ a;
    return {a, b};
}

static u64 chooseForBob(u64 x, u64 y) {
    bool ex = (__builtin_popcountll(x) % 2 == 0);
    bool ey = (__builtin_popcountll(y) % 2 == 0);
    if (ex != ey) return ex ? x : y; 
    if (ex) return max(x, y);        
    
    bool px = isPowerOfTwo(x);
    bool py = isPowerOfTwo(y);
    if (px != py) return px ? y : x;
    return max(x, y);
}

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

    int t = inf.readInt(1, 1000, "t");
    query_limit = 63LL * t;
    log_metrics(); 

    cout << t << endl;

    const long long hard_cap = max(200000LL, 10LL * query_limit);

    for (int tc = 1; tc <= t; ++tc) {
        i64 n_in = inf.readLong(1LL, 1000000000000000000LL, "n");
        u64 n = (u64)n_in;

        cout << n_in << endl;

        string role;
        if (!readToken(role)) finish(_pe, "Unexpected EOF while reading role");
        if (role != "first" && role != "second") finish(_pe, "Role must be 'first' or 'second'");

        bool aliceToBreak = (role == "first");

        u64 fixedP = n;
        bool hasPending = false;
        u64 pendA = 0, pendB = 0;

        long long aliceMovesThisCase = 0;

        while (true) {
            if (aliceToBreak) {
                string sx, sy;
                if (!readToken(sx) || !readToken(sy)) finish(_pe, "Unexpected EOF while reading Alice move");

                i64 ix, iy;
                if (!parseI64(sx, ix) || !parseI64(sy, iy)) finish(_pe, "Alice move must be integers");

                if (ix == 0 && iy == 0) {
                    finish(_wa, "Alice printed 0 0");
                }

                if (ix <= 0 || iy <= 0) {
                    cout << "-1 -1" << endl;
                    finish(_wa, "Alice printed non-positive numbers");
                }

                u64 x = (u64)ix;
                u64 y = (u64)iy;

                u64 p = 0;
                if (hasPending) {
                    p = x ^ y;
                    if (!(p == pendA || p == pendB)) {
                        cout << "-1 -1" << endl;
                        finish(_wa, "Alice broke a number different from the offered choice");
                    }
                } else {
                    p = fixedP;
                    if ((x ^ y) != p) {
                        cout << "-1 -1" << endl;
                        finish(_wa, "XOR does not match current p");
                    }
                }

                if (!(x < p && y < p)) {
                    cout << "-1 -1" << endl;
                    finish(_wa, "Alice printed parts not strictly less than p");
                }

                
                hasPending = false;

                ++aliceMovesThisCase;
                ++queries;

                if (queries > hard_cap) finish(_pe, "Hard cap exceeded");

                if (aliceMovesThisCase > 63) {
                    cout << "-1 -1" << endl;
                    finish(_wa, "Alice exceeded 63 moves");
                }

                
                if (aliceMovesThisCase == 63) {
                    if (canBreak(x) || canBreak(y)) {
                        cout << "-1 -1" << endl;
                        finish(_wa, "Alice reached 63 moves but Bob can still break");
                    } else {
                        
                        cout << "0 0" << endl;
                        break;
                    }
                }

                fixedP = chooseForBob(x, y);
                aliceToBreak = false;
            } else {
                
                if (!canBreak(fixedP)) {
                    cout << "0 0" << endl;
                    break;
                }

                auto [a, b] = splitLowbit(fixedP);
                if (a == 0 || b == 0 || a >= fixedP || b >= fixedP || (a ^ b) != fixedP) {
                    finish(_fail, "Internal error: invalid Bob split");
                }

                cout << (i64)a << " " << (i64)b << endl;

                pendA = a;
                pendB = b;
                hasPending = true;
                aliceToBreak = true;
            }
        }
    }

    finish(_ok, "OK");
}


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

using u64 = unsigned long long;

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

static bool isPowerOfTwo(u64 x) {
    return x && ((x & (x - 1)) == 0);
}

static int poppar(u64 x) {
    return __builtin_popcountll(x) & 1;
}

static u64 lowbit(u64 x) {
    return x & (~x + 1);
}

static u64 msbPow2(u64 x) {
    
    int b = 63 - __builtin_clzll(x);
    return 1ULL << b;
}

static bool readToken(string& s) {
    s.clear();
    return (cin >> s) ? true : false;
}

static bool readU64(u64& x) {
    string s;
    if (!(cin >> s)) return false;
    if (s.empty()) return false;
    if (s.size() > 1 && s[0] == '+') s.erase(s.begin());
    if (s.empty()) return false;
    for (char c : s) if (c < '0' || c > '9') return false;
    if (s.size() > 20) return false;
    __int128 v = 0;
    for (char c : s) {
        v = v * 10 + (c - '0');
        if (v > (__int128)numeric_limits<u64>::max()) return false;
    }
    x = (u64)v;
    return true;
}

struct BestRes {
    int pc = -1;
    u64 val = 0;
    bool ok = false;
};

static u64 chooseNInRangeMaxPopcount(u64 L, u64 R) {
    
    static BestRes memo[64][2][2];
    static bool vis[64][2][2];

    auto better = [](const BestRes& a, const BestRes& b) -> bool {
        if (!a.ok) return false;
        if (!b.ok) return true;
        if (a.pc != b.pc) return a.pc > b.pc;
        return a.val > b.val;
    };

    function<BestRes(int, int, int)> dfs = [&](int bit, int tightL, int tightR) -> BestRes {
        if (bit < 0) {
            BestRes base;
            base.pc = 0;
            base.val = 0;
            base.ok = true;
            return base;
        }
        if (vis[bit][tightL][tightR]) return memo[bit][tightL][tightR];
        vis[bit][tightL][tightR] = true;

        int lb = tightL ? int((L >> bit) & 1ULL) : 0;
        int ub = tightR ? int((R >> bit) & 1ULL) : 1;

        BestRes best;
        best.ok = false;

        if (lb > ub) {
            memo[bit][tightL][tightR] = best;
            return best;
        }

        
        for (int v = ub; v >= lb; --v) {
            int ntL = tightL && (v == lb);
            int ntR = tightR && (v == ub);
            BestRes sub = dfs(bit - 1, ntL, ntR);
            if (!sub.ok) continue;
            BestRes cur;
            cur.ok = true;
            cur.pc = sub.pc + v;
            cur.val = sub.val | (u64(v) << bit);
            if (!best.ok || better(cur, best)) best = cur;
        }

        memo[bit][tightL][tightR] = best;
        return best;
    };

    memset(vis, 0, sizeof(vis));
    int topBit = 0;
    for (int b = 63; b >= 0; --b) {
        if (((R >> b) & 1ULL) || ((L >> b) & 1ULL)) {
            topBit = b;
            break;
        }
    }
    BestRes ans = dfs(topBit, 1, 1);
    if (!ans.ok) return L; 
    if (ans.val < L) return L;
    if (ans.val > R) return R;
    return ans.val;
}

static bool validSplit(u64 p, u64 a, u64 b) {
    if (a == 0 || b == 0) return false;
    if (!(a < p && b < p)) return false;
    if ( (a ^ b) != p ) return false;
    return true;
}

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

    int t = 0;
    try {
        t = inf.readInt(1, 1000, "t");
    } catch (...) {
        finish(_pe, "failed to read t from inf");
    }

    query_limit = 63LL * t;
    log_metrics(); 

    long long hard_cap = max(200000LL, 10LL * query_limit);

    cout << t << endl;
    cout.flush();

    for (int tc = 1; tc <= t; ++tc) {
        string line;
        
        while (true) {
            if (inf.eof()) finish(_pe, "unexpected eof in inf");
            line = inf.readLine();
            bool any = false;
            for (char c : line) if (!isspace((unsigned char)c)) { any = true; break; }
            if (any) break;
        }

        stringstream ss(line);
        unsigned long long a = 0, b = 0;
        if (!(ss >> a)) finish(_pe, "bad line in inf");
        if (ss >> b) {
            u64 L = a, R = b;
            if (L < 1) L = 1;
            if (R < 1) R = 1;
            if (L > R) swap(L, R);
            u64 n = chooseNInRangeMaxPopcount(L, R);
            cout << n << endl;
        } else {
            u64 n = a;
            if (n < 1) n = 1;
            cout << n << endl;
        }
        cout.flush();

        
        ss.clear();
        ss.str(line);
        u64 first = 0, second = 0;
        ss >> first;
        bool hasSecond = bool(ss >> second);
        u64 n = 0;
        if (!hasSecond) {
            n = first < 1 ? 1ULL : first;
        } else {
            u64 L = first, R = second;
            if (L < 1) L = 1;
            if (R < 1) R = 1;
            if (L > R) swap(L, R);
            n = chooseNInRangeMaxPopcount(L, R);
        }

        string who;
        if (!readToken(who)) finish(_pe, "EOF while reading first/second");
        for (char& c : who) c = (char)tolower((unsigned char)c);

        bool aliceBreaks = false;
        if (who == "first") aliceBreaks = true;
        else if (who == "second") aliceBreaks = false;
        else finish(_pe, "expected first/second");

        long long aliceMovesThisCase = 0;

        
        
        bool aliceHasChoice = false;
        u64 offer1 = 0, offer2 = 0;

        
        u64 bobCurrent = n;

        while (true) {
            if (aliceBreaks) {
                u64 p1 = 0, p2 = 0;
                if (!readU64(p1) || !readU64(p2)) finish(_pe, "bad/missing Alice move");
                if (p1 == 0 && p2 == 0) {
                    
                    cout << "-1 -1" << endl;
                    cout.flush();
                    finish(_wa, "Alice output 0 0");
                }

                u64 p = p1 ^ p2;

                if (!aliceHasChoice) {
                    
                    if (p != n) {
                        cout << "-1 -1" << endl;
                        cout.flush();
                        finish(_wa, "Alice broke wrong number");
                    }
                } else {
                    if (!(p == offer1 || p == offer2)) {
                        cout << "-1 -1" << endl;
                        cout.flush();
                        finish(_wa, "Alice did not choose a valid offered number");
                    }
                }

                if (isPowerOfTwo(p)) {
                    cout << "-1 -1" << endl;
                    cout.flush();
                    finish(_wa, "Alice attempted to break a power of two");
                }
                if (!validSplit(p, p1, p2)) {
                    cout << "-1 -1" << endl;
                    cout.flush();
                    finish(_wa, "invalid split by Alice");
                }

                ++queries;
                ++aliceMovesThisCase;
                if (queries > hard_cap) finish(_pe, "too many queries (hard cap exceeded)");
                if (aliceMovesThisCase > 63) {
                    cout << "-1 -1" << endl;
                    cout.flush();
                    finish(_wa, "Alice exceeded 63 turns");
                }

                
                auto chooseForBob = [&](u64 x, u64 y) -> u64 {
                    
                    if (isPowerOfTwo(x) && !isPowerOfTwo(y)) return y;
                    if (isPowerOfTwo(y) && !isPowerOfTwo(x)) return x;

                    int px = poppar(x);
                    int py = poppar(y);

                    
                    if (px != py) {
                        if (px == 0) return x;
                        return y;
                    }

                    
                    bool xP2 = isPowerOfTwo(x), yP2 = isPowerOfTwo(y);
                    if (xP2 != yP2) return xP2 ? y : x;
                    if (x != y) return max(x, y);
                    return x;
                };

                bobCurrent = chooseForBob(p1, p2);
                aliceHasChoice = false;
                aliceBreaks = false;
            } else {
                
                if (isPowerOfTwo(bobCurrent)) {
                    cout << "0 0" << endl;
                    cout.flush();
                    break; 
                }

                if (aliceMovesThisCase >= 63) {
                    
                    cout << "-1 -1" << endl;
                    cout.flush();
                    finish(_wa, "Alice did not win within 63 turns");
                }

                u64 x = 0, y = 0;
                if (poppar(bobCurrent) == 0) {
                    
                    u64 h = msbPow2(bobCurrent);
                    if (h == bobCurrent) {
                        
                        cout << "0 0" << endl;
                        cout.flush();
                        break;
                    }
                    x = h;
                    y = bobCurrent ^ x; 
                } else {
                    
                    x = lowbit(bobCurrent);
                    if (x == bobCurrent) {
                        
                        cout << "0 0" << endl;
                        cout.flush();
                        break;
                    }
                    y = bobCurrent ^ x; 
                }

                if (!validSplit(bobCurrent, x, y)) {
                    finish(_pe, "internal error: produced invalid Bob split");
                }

                cout << x << " " << y << endl;
                cout.flush();

                offer1 = x;
                offer2 = y;
                aliceHasChoice = true;
                aliceBreaks = true;
            }
        }
    }

    finish(_ok, "ok");
}


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

using u64 = unsigned long long;
using i64 = long long;

static bool isPowerOfTwo(u64 x) {
    return x && ((x & (x - 1)) == 0);
}

static int msbPos(u64 x) {
    int p = -1;
    while (x) {
        ++p;
        x >>= 1;
    }
    return p;
}

static u64 clampU64(u64 x, u64 lo, u64 hi) {
    if (x < lo) return lo;
    if (x > hi) return hi;
    return x;
}

static u64 genHardFixedN(u64 maxn, long long seedVal) {
    if (maxn < 1) return 1;

    int high = msbPos(maxn); 
    if (high < 0) return 1;

    auto safePow2 = [&](int b) -> u64 {
        if (b < 0) return 0;
        if (b >= 63) return (u64(1) << 62); 
        return (u64(1) << b);
    };

    
    if (seedVal == 1) return 1;
    if (seedVal == 2) {
        u64 p = safePow2(high);
        while (p > maxn) p >>= 1;
        if (p < 1) p = 1;
        return p;
    }
    if (seedVal == 3) {
        u64 p = safePow2(high);
        while (p > maxn) p >>= 1;
        u64 m = (p > 1 ? (p - 1) : 1);
        if (m < 1) m = 1;
        return m;
    }

    vector<u64> candidates;

    u64 top = safePow2(high);
    while (top > maxn) top >>= 1;

    
    if (top >= 4) candidates.push_back(top - 1);

    
    if (high >= 1) {
        u64 x = safePow2(high) + safePow2(high - 1);
        if (x > 0) x -= 1;
        if (x >= 1 && x <= maxn) candidates.push_back(x);
    }

    
    if (maxn >= 2) candidates.push_back(maxn - 1);

    
    {
        u64 x = safePow2(high);
        int parity = rnd.next(0, 1);
        for (int b = high - 1; b >= 0; --b) {
            if ((b & 1) == parity) x |= safePow2(b);
        }
        if (x >= 1 && x <= maxn) candidates.push_back(x);
    }

    
    if (high >= 10) {
        int low = rnd.next(8, min(20, high - 1));
        u64 x = safePow2(high);
        u64 block = safePow2(low) - 1;
        if (x + block <= maxn) candidates.push_back(x + block);
    }

    
    if (!candidates.empty() && rnd.next(0, 99) < 55) {
        u64 x = candidates[rnd.next(0, (int)candidates.size() - 1)];
        if (x < 1) x = 1;
        if (x > maxn) x = maxn;
        if (isPowerOfTwo(x) && x > 1) x ^= 1ULL;
        if (x < 1) x = 1;
        if (x > maxn) x = maxn;
        if (isPowerOfTwo(x) && x + 1 <= maxn) x += 1;
        return x;
    }

    
    for (int it = 0; it < 200; ++it) {
        int hbLo = max(0, high - 6);
        int hb = rnd.next(hbLo, high);
        u64 x = safePow2(hb);

        
        int pnum = rnd.next(65, 90); 
        for (int b = hb - 1; b >= 0; --b) {
            if (rnd.next(0, 99) < pnum) x |= safePow2(b);
        }

        
        if (isPowerOfTwo(x)) {
            int addb = (hb == 0 ? 0 : rnd.next(0, hb - 1));
            x |= safePow2(addb);
        }

        if (x >= 1 && x <= maxn) return x;
    }

    
    u64 fallback = (top >= 4 ? top - 1 : maxn);
    fallback = clampU64(fallback, 1, maxn);
    if (isPowerOfTwo(fallback) && fallback + 1 <= maxn) fallback += 1;
    if (fallback < 1) fallback = 1;
    return fallback;
}

int main(int argc, char** argv) {
    registerGen(argc, argv, 1);

    string mode = opt<string>("mode", "non");
    long long seedVal = 0;
    if (argc >= 2) {
        try {
            seedVal = stoll(string(argv[1]));
        } catch (...) {
            seedVal = 0;
        }
    }

    u64 maxn = (u64)opt<long long>("maxn", 1000000000000000000LL);
    if (maxn < 1) maxn = 1;

    if (mode != "non" && mode != "adp") mode = "non";

    if (mode == "non") {
        u64 n = genHardFixedN(maxn, seedVal);
        cout << 1 << "\n" << n << "\n";
        return 0;
    }

    
    
    u64 center = genHardFixedN(maxn, seedVal);

    
    if (seedVal >= 1 && seedVal <= 3) {
        cout << 1 << "\n" << center << " " << center << "\n";
        return 0;
    }

    int high = msbPos(maxn);
    int wexpLo = 18;
    int wexpHi = min(26, max(18, high - 20));
    int wexp = rnd.next(wexpLo, wexpHi);
    u64 width = (wexp >= 63 ? (u64)-1 : ((u64)1 << wexp));
    if (width > 0) width -= 1;

    u64 L = (center > width ? center - width : 1ULL);
    u64 R = center + width;
    if (R > maxn || R < center) R = maxn;

    
    if (rnd.next(0, 99) < 60) {
        u64 capR = maxn;
        u64 capL = (maxn > width ? maxn - width : 1ULL);
        if (capL <= capR) {
            L = max(L, capL);
            R = capR;
        }
    }

    L = clampU64(L, 1, maxn);
    R = clampU64(R, 1, maxn);
    if (L > R) swap(L, R);

    cout << 1 << "\n" << L << " " << R << "\n";
    return 0;
}