#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
int main() {
int n;
cin >> n;
auto query = [&](const vector<string> &out) {
cout << "?" << endl;
for (auto &i : out) {
cout << i << endl;
}
int x;
cin >> x;
return x;
};
auto answer = [&](const vector<string> &out) {
cout << "!" << endl;
for (auto &i : out) {
cout << i << endl;
}
};
auto is_same_as = [&](int i1, int j1, int i2, int j2) {
vector out(n, string(n, '0'));
out[i1][j1] = out[i2][j2] = '1';
return query(out) % n == 0;
};
auto run_bs = [&](char c) {
// vector<string> grid(n, string(n, c));
// for (int i = 0; i < n; ++i) {
// for (int j = 0; j < n; ++j) {
// if (i == 0 && j == 0) {
// continue;
// }
// if (!is_same_as(0, 0, i, j)) {
// grid[i][j] = c == 'V' ? 'H' : 'V';
// }
// }
// }
vector<bool> row_has_horizontal(n), col_has_vertical(n);
for (int i = 0; i < n; ++i) {
vector<string> out(n, string(n, '0'));
out[i] = string(n, '1');
row_has_horizontal[i] = query(out) != n * n;
if (!row_has_horizontal[i]) {
return out;
}
}
for (int i = 0; i < n; ++i) {
vector<string> out(n, string(n, '0'));
for (int j = 0; j < n; ++j) {
out[j][i] = '1';
}
col_has_vertical[i] = query(out) != n * n;
if (!col_has_vertical[i]) {
return out;
}
}
vector dp(n + 1, vector<int>(n + 1, inf));
for (int i = n; i >= 0; --i) {
for (int j = n; j >= 0; --j) {
if (i == n || j == n) {
dp[i][j] = 0;
continue;
}
if (row_has_horizontal[i]) {
dp[i][j] = min(dp[i][j], dp[i + 1][j] + 1);
}
if (col_has_vertical[j]) {
dp[i][j] = min(dp[i][j], dp[i][j + 1] + 1);
}
}
}
vector<string> out(n, string(n, '0'));
int i = 0, j = 0;
while (i < n && j < n) {
bool found = false;
if (row_has_horizontal[i] && dp[i][j] == dp[i + 1][j] + 1) {
int jj = *ranges::partition_point(views::iota(0, n), [&](int jj) {
if (jj == 0) {
return bool(is_same_as(0, 0, i, jj) ^ (c != 'V'));
}
vector out(n, string(n, '0'));
for (int _ = 0; _ <= jj; ++_) {
out[i][_] = '1';
}
return query(out) == (jj + 1) * n;
});
out[i++][jj] = '1';
found = true;
}
if (!found && col_has_vertical[j] && dp[i][j] == dp[i][j + 1] + 1) {
int ii = *ranges::partition_point(views::iota(0, n), [&](int ii) {
if (ii == 0) {
return bool(is_same_as(0, 0, ii, j) ^ (c != 'H'));
}
vector out(n, string(n, '0'));
for (int _ = 0; _ <= ii; ++_) {
out[_][j] = '1';
}
return query(out) == (ii + 1) * n;
});
out[ii][j++] = '1';
}
}
return out;
};
string s = "VH";
random_device rd;
if (rd() & 1) {
swap(s[0], s[1]);
}
for (char &i : s) {
auto out = run_bs(i);
if (query(out) == n * n) {
answer(out);
return 0;
}
}
}