// AC 100

// Model solution

// Phase 1: Circle
// Phase 2: Similar to sebastian_1.5n.cpp, but try to leverage failures better:
//          Initially build a single chain, appending two nodes to it at a time.
//          If a pair fails to append, hold it in "rejected". After the next success,
//          try the rejected pairs again (before any others). Probability of success for
//          these is 2/3 (improved from ~ 1/2).

#include <iostream>
#include <vector>
#include <map>
#include <random>
#include <algorithm>
#include <cassert>

using namespace std;
using ll = long long;

#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
// mt19937 mt(time(0));
mt19937 mt(1337);

map<pair<ll, ll>, bool> mem;
bool ask(ll u, ll v) {
    if (u > v) return !ask(v, u);
    if (mem.count({u, v})) return mem[{u, v}];
    cout << "? " << u+1 << " " << v+1 << endl;
    char r;
    cin >> r;
    return mem[{u, v}] = r == '>';
}

void solve(ll n) {
    mem.clear();

    // initialize length 2 paths
    vector<vector<ll>> paths;
    for (ll i = 0; i < n/2; i++) {
        if (ask(2*i, 2*i+1)) paths.push_back({2*i, 2*i+1});
        else paths.push_back({2*i+1, 2*i});
    }
    if (n & 1) paths.push_back({n-1});

    auto split_random_path = [&]() {
        int msz = 0;
        for (int i = 0; i < sz(paths); ++i) msz = max(msz, sz(paths[i]));
        if (msz <= 1) return;
        ll i;
        do i = mt() % sz(paths);
        while (sz(paths[i]) < 2);
        ll k = 1 + mt() % (sz(paths[i]) - 1);
        paths.emplace_back(paths[i].begin() + k, paths[i].end());
        paths[i].erase(paths[i].begin() + k, paths[i].end());
    };

    ll bad_iterations = 0, good_it = 0;
    bool strategy = 1;
    vector<vector<ll>> rejected[2];
    auto stop_strategy = [&] () {
        strategy = 0;
        paths.insert(paths.end(), all(rejected[0]));
        paths.insert(paths.end(), all(rejected[1]));
        rejected[0].clear();
        rejected[1].clear();
    };
    merge_paths:
    ll a = 0, b = 0;
    while (sz(paths) + sz(rejected[0]) + sz(rejected[1]) > 1) {
        auto &rej = rejected[(good_it+1) % 2];
        if (strategy && sz(rej)) {
            if (ask(paths[a].back(), rej.back().front())) {
                paths[a].insert(paths[a].end(), all(rej.back()));
                rej.pop_back();
                good_it++;
                paths.insert(paths.end(), all(rejected[good_it % 2]));
                rejected[good_it % 2].clear();
            } else {
                paths.push_back(std::move(rej.back()));
                rej.pop_back();
                bad_iterations++;
            }
            continue;
        } else if (strategy && sz(paths) == 1) stop_strategy();
        if (!strategy) {
            a = mt() % sz(paths);
        }
        b = mt() % sz(paths);
        if (a == b) continue;
        if (ask(paths[a].back(), paths[b].front())) {
            paths[a].insert(paths[a].end(), all(paths[b]));
            paths.erase(paths.begin() + b);
            good_it++;
            paths.insert(paths.end(), all(rejected[good_it % 2]));
            rejected[good_it % 2].clear();
        } else if (++bad_iterations % (max(n, 10ll)) == 0) {
            stop_strategy();
            split_random_path();
        } else if (strategy) {
            swap(paths[b], paths.back());
            rejected[good_it % 2].push_back(paths.back());
            paths.pop_back();
        }
    }
    if (!ask(paths[0].back(), paths[0][0])) {
        stop_strategy();
        split_random_path();
        split_random_path();
        goto merge_paths;
    }

    // verify correctness
    for (ll i = 0; i+1 < n; i++) {
        assert(ask(paths[0][i], paths[0][i+1]));
    }
    assert(ask(paths[0].back(), paths[0][0]));

    cout << "! ";
    for (ll i = 0; i < n; i++) {
        cout << paths[0][i]+1 << " ";
    }
    cout << endl;
}
int main() {
    int n, t;
    cin >> n >> t;

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (i != j && (j > i) != (abs(j-i) <= n/2)) cout << 1;
            else cout << 0;
        }
        cout << endl;
    }

    for (int ti = 0; ti < t; ++ti) solve(n);
}
