Problem: cf1970_d2
Difficulty: medium
Categories: data structures, math
Time limit: 5000 ms, memory limit: 256 MB

The only difference between the versions of this problem is the maximum value of $n$.

Professor Vector is preparing to teach her Arithmancy class. She needs to prepare $n$ distinct magic words for the class. Each magic word is a string consisting of characters X and O. A spell is a string created by concatenating two magic words together. The power of a spell is equal to the number of its different non-empty substrings. For example, the power of the spell XOXO is equal to 7, because it has 7 different substrings: X, O, XO, OX, XOX, OXO and XOXO.

Each student will create their own spell by concatenating two magic words. Since the students are not very good at magic yet, they will choose each of the two words independently and uniformly at random from the $n$ words provided by Professor Vector. It is therefore also possible that the two words a student chooses are the same. Each student will then compute the power of their spell, and tell it to Professor Vector. In order to check their work, and of course to impress the students, Professor Vector needs to find out which two magic words and in which order were concatenated by each student.

Your program needs to perform the role of Professor Vector: first, create $n$ distinct magic words, and then handle multiple requests where it is given the spell power and needs to determine the indices of the two magic words, in the correct order, that were used to create the corresponding spell.

Interaction

This is an interactive problem.

First, your program should read a single integer $n$ ($1 \le n \le 30$), the number of magic words to prepare. Then, it should print $n$ magic words it has created, one per line. The magic words must be distinct, each magic word must have at least 1 and at most $30\cdot n$ characters, and each character must be either X or O. We will denote the $i$-th magic word you printed as $w_i$ ($1 \le i \le n$).

Then, your program should read a single integer $q$ ($1 \le q \le 1000$), the number of students in the class. Then, it should repeat the following process $q$ times, one per student.

For the $j$-th student, it should first read a single integer $p_j$, the power of their spell. It is guaranteed that this number is computed by choosing two indices $u_j$ and $v_j$ independently and uniformly at random between 1 and $n$ inclusive, concatenating $w_{u_j}$ and $w_{v_j}$, and finding the number of different non-empty substrings of the resulting string. Then, your program must print the numbers $u_j$ and $v_j$, in this order ($1 \le u_j, v_j \le n$).

Note that it is not enough to find any two magic words that concatenate into a spell with the given power. You must find the exact words used by the student in the exact order.

Remember to flush the output stream after printing all magic words and after printing $u_j$ and $v_j$ for each student.

Example

Input

```
2

2
15

11
```

Output

```
XOXO
X

1 1

2 1
```

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 << "\n";
        tout << "query_limit=" << query_limit << "\n";
        tout.flush();
    } catch (...) {
        
    }
}

static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

static bool isValidIntToken(const string& s) {
    if (s.empty()) return false;
    int i = 0;
    if (s[0] == '+' || s[0] == '-') {
        if (s.size() == 1) return false;
        i = 1;
    }
    for (; i < (int)s.size(); i++) if (s[i] < '0' || s[i] > '9') return false;
    return true;
}

static bool parseLL(const string& tok, long long& out) {
    if (!isValidIntToken(tok)) return false;
    try {
        size_t idx = 0;
        long long v = stoll(tok, &idx, 10);
        if (idx != tok.size()) return false;
        out = v;
        return true;
    } catch (...) {
        return false;
    }
}

struct SAM {
    vector<array<int, 2>> next;
    vector<int> link;
    vector<int> length;
    int last = 0;

    void init(int maxLen) {
        next.assign(2 * maxLen + 1, array<int, 2>{-1, -1});
        link.assign(2 * maxLen + 1, -1);
        length.assign(2 * maxLen + 1, 0);
        last = 0;
        next[0] = {-1, -1};
        link[0] = -1;
        length[0] = 0;
        sz = 1;
    }

    int sz = 1;

    void extend(int c) {
        int cur = sz++;
        length[cur] = length[last] + 1;
        next[cur] = {-1, -1};

        int p = last;
        while (p != -1 && next[p][c] == -1) {
            next[p][c] = cur;
            p = link[p];
        }
        if (p == -1) {
            link[cur] = 0;
        } else {
            int q = next[p][c];
            if (length[p] + 1 == length[q]) {
                link[cur] = q;
            } else {
                int clone = sz++;
                next[clone] = next[q];
                length[clone] = length[p] + 1;
                link[clone] = link[q];

                while (p != -1 && next[p][c] == q) {
                    next[p][c] = clone;
                    p = link[p];
                }
                link[q] = link[cur] = clone;
            }
        }
        last = cur;
    }

    long long distinctSubstringsNonEmpty() const {
        long long ans = 0;
        for (int v = 1; v < sz; v++) {
            int parent = link[v];
            int parentLen = (parent == -1 ? 0 : length[parent]);
            ans += (long long)length[v] - (long long)parentLen;
        }
        return ans;
    }
};

static long long spellPower(const string& s) {
    SAM sam;
    sam.init((int)s.size());
    for (char ch : s) {
        int c = (ch == 'O') ? 0 : 1; 
        sam.extend(c);
    }
    return sam.distinctSubstringsNonEmpty();
}

static bool readTokenFromContestant(string& tok) {
    if (!(cin >> tok)) return false;
    return true;
}

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

    try {
        int n = inf.readInt(1, 30, "n");
        int q = inf.readInt(1, 1000, "q");

        vector<pair<int, int>> hiddenPairs;
        hiddenPairs.reserve(q);
        for (int i = 0; i < q; i++) {
            int u = inf.readInt(1, n, "u");
            int v = inf.readInt(1, n, "v");
            hiddenPairs.push_back({u, v});
        }

        query_limit = q;
        log_metrics(); 

        
        cout << n << "\n";
        cout.flush();

        
        const int maxLen = 30 * n;
        vector<string> words(n + 1);
        set<string> seen;

        for (int i = 1; i <= n; i++) {
            string w;
            if (!readTokenFromContestant(w)) {
                finish(_pe, "EOF while reading magic words");
            }
            if ((int)w.size() < 1 || (int)w.size() > maxLen) {
                finish(_pe, "Magic word length out of bounds");
            }
            for (char ch : w) {
                if (ch != 'X' && ch != 'O') {
                    finish(_pe, "Magic word contains invalid character");
                }
            }
            if (seen.count(w)) {
                finish(_pe, "Magic words must be distinct");
            }
            seen.insert(w);
            words[i] = w;
        }

        
        cout << q << "\n";
        cout.flush();

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

        
        for (int i = 0; i < q; i++) {
            int u = hiddenPairs[i].first;
            int v = hiddenPairs[i].second;

            string s = words[u] + words[v];
            long long p = spellPower(s);

            
            cout << p << "\n";
            cout.flush();

            queries++;
            if (queries > hard_cap) finish(_pe, "Hard cap exceeded (too many interactions)");

            
            string tokU, tokV;
            if (!readTokenFromContestant(tokU) || !readTokenFromContestant(tokV)) {
                finish(_pe, "EOF while reading contestant answer");
            }
            long long ansU, ansV;
            if (!parseLL(tokU, ansU) || !parseLL(tokV, ansV)) {
                finish(_pe, "Non-integer contestant answer");
            }
            if (ansU < 1 || ansU > n || ansV < 1 || ansV > n) {
                finish(_pe, "Contestant answer indices out of range");
            }
            if ((int)ansU != u || (int)ansV != v) {
                finish(_wa, "Wrong pair");
            }
        }

        finish(_ok, "OK");
    } catch (const std::exception& e) {
        finish(_pe, string("Exception: ") + e.what());
    } catch (...) {
        finish(_pe, "Unknown exception");
    }
}


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 << "\n";
        tout << "query_limit=" << query_limit << "\n";
        tout.flush();
    } catch (...) {
        
    }
}

static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

struct SAM {
    struct State {
        int link = -1;
        int len = 0;
        array<int, 2> next{{-1, -1}};
    };

    vector<State> st;
    int last = 0;

    SAM(int maxLen = 0) {
        st.reserve(max(1, 2 * maxLen));
        st.push_back(State());
        last = 0;
    }

    void extend(int c) {
        int cur = (int)st.size();
        st.push_back(State());
        st[cur].len = st[last].len + 1;

        int p = last;
        while (p != -1 && st[p].next[c] == -1) {
            st[p].next[c] = cur;
            p = st[p].link;
        }
        if (p == -1) {
            st[cur].link = 0;
        } else {
            int q = st[p].next[c];
            if (st[p].len + 1 == st[q].len) {
                st[cur].link = q;
            } else {
                int clone = (int)st.size();
                st.push_back(st[q]);
                st[clone].len = st[p].len + 1;
                while (p != -1 && st[p].next[c] == q) {
                    st[p].next[c] = clone;
                    p = st[p].link;
                }
                st[q].link = st[cur].link = clone;
            }
        }
        last = cur;
    }

    long long distinctSubstrings() const {
        long long ans = 0;
        for (int i = 1; i < (int)st.size(); i++) {
            int parent = st[i].link;
            int parentLen = (parent == -1 ? 0 : st[parent].len);
            ans += (long long)st[i].len - parentLen;
        }
        return ans;
    }
};

static bool isXO(const string& s) {
    for (char ch : s) if (ch != 'X' && ch != 'O') return false;
    return true;
}

static long long powerOfConcat(const string& a, const string& b) {
    string s;
    s.reserve(a.size() + b.size());
    s += a;
    s += b;
    SAM sam((int)s.size());
    for (char ch : s) sam.extend(ch == 'X' ? 0 : 1);
    return sam.distinctSubstrings();
}

static bool readTokenSafe(string& out) {
    out.clear();
    if (!(cin >> out)) return false;
    return true;
}

static bool readLongLongSafe(long long& out) {
    out = 0;
    string tok;
    if (!readTokenSafe(tok)) return false;
    int i = 0;
    bool neg = false;
    if (tok[i] == '+' || tok[i] == '-') {
        neg = (tok[i] == '-');
        i++;
    }
    if (i >= (int)tok.size()) return false;
    long long val = 0;
    for (; i < (int)tok.size(); i++) {
        if (tok[i] < '0' || tok[i] > '9') return false;
        int d = tok[i] - '0';
        if (val > (LLONG_MAX - d) / 10) return false;
        val = val * 10 + d;
    }
    out = neg ? -val : val;
    return true;
}

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

    int n = inf.readInt(1, 30, "n");
    int q = inf.readInt(1, 1000, "q");
    query_limit = q;

    
    vector<int> rem;
    while (!inf.seekEof()) rem.push_back(inf.readInt());

    bool fixedPairsMode = false;
    vector<pair<int,int>> fixedPairs;
    if ((int)rem.size() >= 2 * q) {
        fixedPairsMode = true;
        fixedPairs.reserve(q);
        for (int i = 0; i < q; i++) {
            int u = rem[2 * i];
            int v = rem[2 * i + 1];
            if (u < 1 || u > n || v < 1 || v > n) {
                finish(_pe, "invalid (u,v) in hidden input");
            }
            fixedPairs.push_back({u, v});
        }
    } else {
        
        fixedPairsMode = false;
    }

    
    cout << n << "\n";
    cout.flush();

    log_metrics(); 

    vector<string> w(n + 1);
    unordered_set<string> seen;
    seen.reserve(n * 2);

    int maxLen = 30 * n;

    for (int i = 1; i <= n; i++) {
        string s;
        if (!readTokenSafe(s)) finish(_pe, "unexpected EOF while reading magic words");
        if ((int)s.size() < 1 || (int)s.size() > maxLen) finish(_pe, "magic word length out of range");
        if (!isXO(s)) finish(_pe, "magic word contains invalid characters");
        if (seen.count(s)) finish(_pe, "magic words must be distinct");
        seen.insert(s);
        w[i] = s;
    }

    
    vector<vector<long long>> pw(n + 1, vector<long long>(n + 1, 0));
    map<long long, vector<pair<int,int>>> groups;
    for (int u = 1; u <= n; u++) {
        for (int v = 1; v <= n; v++) {
            long long p = powerOfConcat(w[u], w[v]);
            pw[u][v] = p;
            groups[p].push_back({u, v});
        }
    }

    
    cout << q << "\n";
    cout.flush();

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

    if (fixedPairsMode) {
        for (int i = 0; i < q; i++) {
            int u = fixedPairs[i].first;
            int v = fixedPairs[i].second;
            long long p = pw[u][v];

            cout << p << "\n";
            cout.flush();

            long long ru, rv;
            if (!readLongLongSafe(ru) || !readLongLongSafe(rv)) finish(_pe, "unexpected EOF while reading answer");
            if (ru < 1 || ru > n || rv < 1 || rv > n) finish(_pe, "answer indices out of range");

            queries++;
            if (queries > hard_cap) finish(_pe, "too many queries (hard cap exceeded)");

            if ((int)ru != u || (int)rv != v) finish(_wa, "wrong (u,v) for non-adaptive case");
        }
        finish(_ok, "ok");
    } else {
        
        for (int i = 0; i < q; i++) {
            long long bestP = -1;
            int bestSz = -1;
            for (const auto& kv : groups) {
                int sz = (int)kv.second.size();
                if (sz > bestSz || (sz == bestSz && (bestP == -1 || kv.first < bestP))) {
                    bestSz = sz;
                    bestP = kv.first;
                }
            }
            if (bestP == -1) finish(_pe, "internal error: no possible powers");

            cout << bestP << "\n";
            cout.flush();

            long long ru, rv;
            if (!readLongLongSafe(ru) || !readLongLongSafe(rv)) finish(_pe, "unexpected EOF while reading answer");
            if (ru < 1 || ru > n || rv < 1 || rv > n) finish(_pe, "answer indices out of range");

            queries++;
            if (queries > hard_cap) finish(_pe, "too many queries (hard cap exceeded)");

            const auto& cls = groups[bestP];
            bool inClass = false;
            for (const auto& pr : cls) {
                if (pr.first == (int)ru && pr.second == (int)rv) {
                    inClass = true;
                    break;
                }
            }
            if (!inClass) finish(_wa, "answer does not match the given power");

            
            if ((int)cls.size() >= 2) finish(_wa, "power collision: multiple pairs consistent with the same power");

            
        }
        finish(_ok, "ok");
    }
}


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

static vector<pair<int,int>> shuffledAllPairs(int n) {
    vector<pair<int,int>> all;
    all.reserve(n * n);
    for (int u = 1; u <= n; u++) {
        for (int v = 1; v <= n; v++) all.push_back({u, v});
    }
    for (int i = (int)all.size() - 1; i > 0; i--) {
        int j = rnd.next(0, i);
        swap(all[i], all[j]);
    }
    return all;
}

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

    string mode = opt<string>("mode", "non");
    int nOpt = opt<int>("n", 0);
    int qOpt = opt<int>("q", 0);

    int n, q;

    int seedTag = 0;
    if (argc >= 2) {
        string s = argv[1];
        bool ok = !s.empty();
        int sign = 1, pos = 0;
        if (ok && (s[0] == '-' || s[0] == '+')) { sign = (s[0] == '-') ? -1 : 1; pos = 1; }
        long long val = 0;
        for (int i = pos; i < (int)s.size(); i++) {
            if (s[i] < '0' || s[i] > '9') { ok = false; break; }
            val = val * 10 + (s[i] - '0');
            if (val > 2000000000LL) break;
        }
        if (ok) seedTag = (int)(val * sign);
    }

    if (nOpt > 0) n = nOpt;
    else {
        if (seedTag == 1) n = 1;
        else if (seedTag == 2) n = 30;
        else if (seedTag == 3) n = 30;
        else n = 30;
    }
    if (qOpt > 0) q = qOpt;
    else {
        if (seedTag == 1) q = 1;
        else if (seedTag == 2) q = 1;
        else if (seedTag == 3) q = 1000;
        else q = 1000;
    }

    n = max(1, min(30, n));
    q = max(1, min(1000, q));

    if (mode == "non") {
        cout << n << "\n";
        cout << q << "\n";

        vector<pair<int,int>> pairs;
        pairs.reserve(q);

        if (seedTag >= 1 && seedTag <= 3) {
            for (int i = 0; i < q; i++) {
                int u = rnd.next(1, n);
                int v = rnd.next(1, n);
                pairs.push_back({u, v});
            }
        } else {
            vector<pair<int,int>> all = shuffledAllPairs(n);
            int take = min(q, (int)all.size());
            for (int i = 0; i < take; i++) pairs.push_back(all[i]);

            while ((int)pairs.size() < q) {
                int u = rnd.next(1, n);
                int v = rnd.next(1, n);
                pairs.push_back({u, v});
            }
        }

        for (auto &e : pairs) {
            cout << e.first << " " << e.second << "\n";
        }
    } else if (mode == "adp") {
        cout << n << "\n";
        cout << q << "\n";
        int interactorSeed = rnd.next(1, 1000000000);
        cout << interactorSeed << "\n";
    } else {
        quitf(_fail, "unknown --mode (expected non/adp), got: %s", mode.c_str());
    }

    return 0;
}