#include <iostream>
#include <random>
#include <algorithm>

using namespace std;

void finish_graded_proc() {
    cerr << "kill" << endl;
}
void give_feedback(string s) {
    erase(s, '\n');
    erase(s, '\0');
    if (s != "") {
        if (s.size() > 500) s.resize(500);
        s.insert(0, "feedback ");
        s.push_back('\n');
        cerr << s << flush;
    }
}
void give_scores(vector<int> scores) {
    string s = "scores";
    for (int score : scores) {
        s.push_back(' ');
        s += to_string(score);
    }
    s.push_back('\n');
    cerr << s << flush;
}

// Give numerical grade to the user
[[noreturn]] void grade(int result, string feedback="") {
    give_feedback(std::move(feedback));
    exit(result);
}
// Indicate that program failed to produce the right answer
[[noreturn]] void fail(string feedback="") {
    give_feedback(std::move(feedback));
    finish_graded_proc();
    exit(0);
}
// Indicate that the user output was accepted
[[noreturn]] void accept(string feedback="") {
    give_feedback(std::move(feedback));
    exit(100);
}
#define SAFE_READ(x) \
    do               \
    {                \
        if (!(x))    \
            fail("Formatting error");  \
    } while (false)

mt19937 r_dev;

// Returns a value in range [a, b] inclusive
int rnd(int a, int b) {
    return uniform_int_distribution<int>(a, b)(r_dev);
}
// Shuffles any type with begin and end
template <typename T>
void shuffle(T &arr) {
    shuffle(arr.begin(), arr.end(), r_dev);
}

using Graph = vector<vector<uint8_t>>;

Graph phase1(int n, int t) {
    cout << n << " " << t << endl;

    Graph G(n+1, vector<uint8_t>(n+1));

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            char c;
            cin >> c;
            if (c == '1') G[i][j] = 1;
            else if (c != '0') fail("Invalid character in graph description" + to_string(c) + ".");
            if (i == j && G[i][j]) fail("Self-loop");
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = i+1; j <= n; ++j) {
            if (G[i][j] == G[j][i]) fail("Duplicate or missing edge in given graph");
        }
    }

    return G;
}

const long MAX_QUERIES = 10000;

long phase2(int n, const Graph &G, int rep, const vector<int> &perm) {
    string casestr = "Case #" + to_string(rep + 1) + ": ";

    long query_count = 0;

    while (true) {
        char op;
        SAFE_READ(cin >> op);
        if (op == '?') {
            query_count++;
            if (query_count > MAX_QUERIES) fail(casestr + "Too many queries");
            int u, v;
            SAFE_READ(cin >> u >> v);
            if (u < 1 || u > n || v < 1 || v > n) fail(casestr + "Invalid query");
            if (u == v) fail(casestr + "Invalid query");
            u = perm[u - 1];
            v = perm[v - 1];

            if (G[u][v]) cout << ">" << endl;
            else cout << "<" << endl;
        } else if (op == '!') {
            vector<int> cycle(n), z(n+1);
            for (int i = 0; i < n; ++i) {
                SAFE_READ(cin >> cycle[i]);
                if (cycle[i] < 1 || cycle[i] > n) fail(casestr + "Invalid node in answer");
                if (z[cycle[i]]) fail(casestr + "Duplicate node in answer");
                z[cycle[i]] = 1;
            }
            for (int i = 0; i < n; ++i) {
                int a = cycle[i], b = cycle[(i+1)%n];
                int oa = perm[a - 1], ob = perm[b - 1];
                if (!G[oa][ob]) fail(casestr + "Wrong edge in answer, " + to_string(a) + " to " + to_string(b));
            }

            return query_count;
        } else fail(casestr + "Unexpected operation");
    }
}

int main(int argc, char **argv) {
    // TODO: get rid of this
    cerr << "encoder" << endl;

    int seed, n, t;
    string mode;
    SAFE_READ(cin >> seed >> n >> t >> mode);

    r_dev.seed(seed ^ 0xE28015A6);

    vector<vector<int>> perms;

    if (mode == "rnd") {

    } else if (mode == "fixed") {
        for (int rep = 0; rep < t; ++rep) {
            vector<int> perm(n);
            for (int i = 0; i < n; ++i) {
                int x;
                SAFE_READ(cin >> x);
                if (x < 1 || x > n) throw;
                if (perm[x-1]) throw;
                perm[x-1] = i+1;
            }
            perms.push_back(perm);
        }
    } else throw;

    auto G = phase1(n, t);
    long total = 0;

    for (int rep = 0; rep < t; ++rep) {
        vector<int> perm;
        if (mode == "rnd") {
            perm.resize(n);
            for (int i = 0; i < n; ++i) perm[i] = i+1;
            shuffle(perm);
        } else if (mode == "fixed") {
            perm = perms[rep];
        }

        long queries = phase2(n, G, rep, perm);
        total += queries;
    }

    double Q = double(total) / t;

    vector<int> scores(4, 100);

    if (n == 4) {
        scores[0] = Q <= 12 ? 100 : 0;
    }

    if (n == 50) {
        scores[1] = Q <= 1225 ? 100 : 0;
        scores[2] = Q <= 300 ? 100 : 0;
    }

    if (n == 500) {
        int open_score;
        if (Q <= 1500) {
            open_score = floor(25000. / (max(750., Q) - 500) - 24);
        } else {
            open_score = 0;
        }
        // relative 0 to 100 (map after rounding)
        int open_score_rel = round(100. * open_score / 76.);
        open_score_rel = min(open_score_rel, 100);
        scores[3] = open_score_rel;
    }

    give_scores(scores);

    accept("Q = " + to_string(Q));
}
