Problem: cf1205_c
Difficulty: medium
Categories: graph, math
Time limit: 1000 ms, memory limit: 256 MB

This is an interactive problem

You are given a grid $n\times n$, where $n$ is odd. Rows are enumerated from $1$ to $n$ from up to down, columns are enumerated from $1$ to $n$ from left to right. Cell, standing on the intersection of row $x$ and column $y$, is denoted by $(x, y)$.

Every cell contains $0$ or $1$. It is known that the top-left cell contains $1$, and the bottom-right cell contains $0$.

We want to know numbers in all cells of the grid. To do so we can ask the following questions:

"$?$ $x_1$ $y_1$ $x_2$ $y_2$", where $1 \le x_1 \le x_2 \le n$, $1 \le y_1 \le y_2 \le n$, and $x_1 + y_1 + 2 \le x_2 + y_2$. In other words, we output two different cells $(x_1, y_1)$, $(x_2, y_2)$ of the grid such that we can get from the first to the second by moving only to the right and down, and they aren't adjacent.

As a response to such question you will be told if there exists a path between $(x_1, y_1)$ and $(x_2, y_2)$, going only to the right or down, numbers in cells of which form a palindrome.

For example, paths, shown in green, are palindromic, so answer for "$?$ $1$ $1$ $2$ $3$" and "$?$ $1$ $2$ $3$ $3$" would be that there exists such path. However, there is no palindromic path between $(1, 1)$ and $(3, 1)$.

 ![](https://espresso.codeforces.com/ced4b1f37f0db8117da3c34a0c9eaf1c38426458.png) 

Determine all cells of the grid by asking not more than $n^2$ questions. It can be shown that the answer always exists.

Input

The first line contains odd integer ($3 \le n < 50$) — the side of the grid.

Interaction

You begin the interaction by reading $n$.

To ask a question about cells $(x_1, y_1), (x_2, y_2)$, in a separate line output "$?$ $x_1$ $y_1$ $x_2$ $y_2$".

Numbers in the query have to satisfy $1 \le x_1 \le x_2 \le n$, $1 \le y_1 \le y_2 \le n$, and $x_1 + y_1 + 2 \le x_2 + y_2$. Don't forget to 'flush', to get the answer.

In response, you will receive $1$, if there exists a path going from $(x_1, y_1)$ to $(x_2, y_2)$ only to the right or down, numbers in cells of which form a palindrome, and $0$ otherwise.

In case your query is invalid or you asked more than $n^2$ queries, program will print $-1$ and will finish interaction. You will receive Wrong answer verdict. Make sure to exit immediately to avoid getting other verdicts.

When you determine numbers in all cells, output "!".

Then output $n$ lines, the $i$-th of which is a string of length $n$, corresponding to numbers in the $i$-th row of the grid.

After printing a query do not forget to output 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 documentation for other languages.

Example

Input

```
3
0
1
0
1
1
1
1
```

Output

```
? 1 1 1 3
? 1 1 2 3
? 2 1 2 3
? 3 1 3 3
? 2 2 3 3
? 1 2 3 2
? 1 2 3 3
!
100
001
000
```

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 parseLongLongToken(const string& s, long long& out) {
    if (s.empty()) return false;
    int i = 0;
    bool neg = false;
    if (s[0] == '+' || s[0] == '-') {
        neg = (s[0] == '-');
        i = 1;
        if ((int)s.size() == 1) return false;
    }
    __int128 val = 0;
    for (; i < (int)s.size(); i++) {
        char c = s[i];
        if (c < '0' || c > '9') return false;
        val = val * 10 + (c - '0');
        if (!neg && val > (__int128)LLONG_MAX) return false;
        if (neg && -val < (__int128)LLONG_MIN) return false;
    }
    out = neg ? (long long)(-val) : (long long)val;
    return true;
}

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

static bool readIntInRange(long long& x, long long lo, long long hi) {
    string tok;
    if (!readToken(tok)) return false;
    if (!parseLongLongToken(tok, x)) return false;
    return (lo <= x && x <= hi);
}

static inline int idx4(int n, int x1, int y1, int x2, int y2) {
    return (((x1 * n + y1) * n + x2) * n + y2);
}

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

    int n = 0;
    try {
        n = inf.readInt();
    } catch (...) {
        query_limit = 0;
        log_metrics();
        quitf(_fail, "failed to read n from hidden input");
    }
    if (n < 1 || n > 200) {
        query_limit = 0;
        log_metrics();
        quitf(_fail, "invalid n in hidden input");
    }

    vector<string> g(n);
    for (int i = 0; i < n; i++) {
        string row;
        try {
            row = inf.readToken();
        } catch (...) {
            query_limit = 0;
            log_metrics();
            quitf(_fail, "failed to read grid row from hidden input");
        }
        if ((int)row.size() != n) {
            query_limit = 0;
            log_metrics();
            quitf(_fail, "grid row has invalid length in hidden input");
        }
        for (char c : row) {
            if (c != '0' && c != '1') {
                query_limit = 0;
                log_metrics();
                quitf(_fail, "grid row has invalid character in hidden input");
            }
        }
        g[i] = row;
    }

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

    
    
    vector<uint8_t> dp((size_t)n * n * n * n, 0);

    int maxd = 2 * (n - 1);
    for (int d = 0; d <= maxd; d++) {
        for (int x1 = 0; x1 < n; x1++) {
            for (int y1 = 0; y1 < n; y1++) {
                int maxDx = min(n - 1 - x1, d);
                for (int dx = 0; dx <= maxDx; dx++) {
                    int dy = d - dx;
                    if (dy < 0) continue;
                    if (y1 + dy >= n) continue;
                    int x2 = x1 + dx;
                    int y2 = y1 + dy;

                    int id = idx4(n, x1, y1, x2, y2);
                    if (d == 0) {
                        dp[id] = 1;
                        continue;
                    }
                    if (g[x1][y1] != g[x2][y2]) {
                        dp[id] = 0;
                        continue;
                    }
                    if (d == 1) {
                        dp[id] = 1;
                        continue;
                    }

                    bool ok = false;

                    
                    for (int sm = 0; sm < 2 && !ok; sm++) {
                        int nx1 = x1 + (sm == 0 ? 1 : 0);
                        int ny1 = y1 + (sm == 1 ? 1 : 0);
                        if (nx1 > x2 || ny1 > y2) continue;

                        
                        for (int em = 0; em < 2 && !ok; em++) {
                            int nx2 = x2 - (em == 0 ? 1 : 0);
                            int ny2 = y2 - (em == 1 ? 1 : 0);
                            if (nx2 < x1 || ny2 < y1) continue;
                            if (nx1 > nx2 || ny1 > ny2) continue;

                            int sub = idx4(n, nx1, ny1, nx2, ny2);
                            if (dp[sub]) ok = true;
                        }
                    }
                    dp[id] = ok ? 1 : 0;
                }
            }
        }
    }

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

    
    log_metrics();

    while (true) {
        string cmd;
        if (!readToken(cmd)) {
            
            finish(_pe, "unexpected EOF from contestant");
        }

        if (cmd == "?") {
            long long x1ll, y1ll, x2ll, y2ll;
            if (!readIntInRange(x1ll, 1, n) || !readIntInRange(y1ll, 1, n) ||
                !readIntInRange(x2ll, 1, n) || !readIntInRange(y2ll, 1, n)) {
                cout << -1 << '\n';
                cout.flush();
                finish(_pe, "malformed query coordinates");
            }
            int x1 = (int)x1ll - 1, y1 = (int)y1ll - 1, x2 = (int)x2ll - 1, y2 = (int)y2ll - 1;

            if (!(0 <= x1 && x1 <= x2 && x2 < n && 0 <= y1 && y1 <= y2 && y2 < n)) {
                cout << -1 << '\n';
                cout.flush();
                finish(_pe, "query violates ordering/range constraints");
            }
            int dist = (x2 - x1) + (y2 - y1);
            if (dist < 2) {
                cout << -1 << '\n';
                cout.flush();
                finish(_pe, "query endpoints are adjacent or same (distance < 2)");
            }

            queries++;
            if (queries > hard_cap) {
                cout << -1 << '\n';
                cout.flush();
                finish(_pe, "hard cap exceeded");
            }

            int ans = dp[idx4(n, x1, y1, x2, y2)] ? 1 : 0;
            cout << ans << '\n';
            cout.flush();
        } else if (cmd == "!") {
            vector<string> outg(n);
            for (int i = 0; i < n; i++) {
                string row;
                if (!readToken(row)) {
                    finish(_pe, "unexpected EOF while reading final grid");
                }
                if ((int)row.size() != n) {
                    finish(_pe, "final grid row has invalid length");
                }
                for (char c : row) {
                    if (c != '0' && c != '1') finish(_pe, "final grid row has invalid character");
                }
                outg[i] = row;
            }

            for (int i = 0; i < n; i++) {
                if (outg[i] != g[i]) {
                    finish(_wa, "final grid is incorrect");
                }
            }
            finish(_ok, "ok");
        } else {
            cout << -1 << '\n';
            cout.flush();
            finish(_pe, "unknown command token");
        }
    }
}


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 parseLLStrict(const string& s, long long& out) {
    if (s.empty()) return false;
    int i = 0;
    bool neg = false;
    if (s[i] == '+' || s[i] == '-') {
        neg = (s[i] == '-');
        i++;
        if (i == (int)s.size()) return false;
    }
    long long val = 0;
    for (; i < (int)s.size(); i++) {
        char c = s[i];
        if (c < '0' || c > '9') return false;
        int d = c - '0';
        if (val > (LLONG_MAX - d) / 10) return false;
        val = val * 10 + d;
    }
    out = neg ? -val : val;
    return true;
}

struct GridRep {
    int n = 0;
    vector<uint8_t> val;      
    vector<string> rows;      
};

static int gN = 0;
static int gCells = 0;
static vector<int> gX, gY; 
static vector<int> gDown, gRight, gUp, gLeft;

static inline int idx0(int x0, int y0) { 
    return x0 * gN + y0;
}
static inline int idx1(int x1, int y1) { 
    return (x1 - 1) * gN + (y1 - 1);
}

static GridRep buildRepFromRows(const vector<string>& rows) {
    GridRep rep;
    rep.n = (int)rows.size();
    rep.rows = rows;
    rep.val.assign(rep.n * rep.n, 0);
    for (int i = 0; i < rep.n; i++) {
        for (int j = 0; j < rep.n; j++) {
            rep.val[i * rep.n + j] = (uint8_t)(rows[i][j] == '1');
        }
    }
    return rep;
}

static vector<string> genCandidateRows(int n, int which) {
    vector<string> rows(n, string(n, '0'));
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            int b = 0;
            if (which == 0) {
                int t = (i * 17 + j * 31 + (i * j) % 7);
                b = (t & 1);
                if ((i + j) % 3 == 0) b ^= 1;
                if (i == j || i + j == n + 1) b ^= 1;
            } else if (which == 1) {
                b = ((i + j) % 2 == 0) ? 1 : 0;
                if (i % 7 == 0) b ^= 1;
                if (j % 5 == 0) b ^= 1;
            } else { 
                b = (j % 2 == 1) ? 1 : 0;
                if (i % 4 == 1) b ^= 1;
                if ((i + 2 * j) % 11 == 0) b ^= 1;
            }
            rows[i - 1][j - 1] = char('0' + (b & 1));
        }
    }
    rows[0][0] = '1';
    rows[n - 1][n - 1] = '0';
    return rows;
}

static bool palExists(const GridRep& rep, int x1, int y1, int x2, int y2,
                      vector<int>& seen, int& stamp) {
    
    if (x1 > x2 || y1 > y2) return false;
    int L = (x2 - x1) + (y2 - y1) + 1;
    int a0 = idx1(x1, y1);
    int b0 = idx1(x2, y2);
    if (rep.val[a0] != rep.val[b0]) return false;
    if (L <= 2) return true;

    stamp++;
    if (stamp == INT_MAX) {
        fill(seen.begin(), seen.end(), 0);
        stamp = 1;
    }

    const int cells = gCells;
    auto keyOf = [&](int a, int b) -> int { return a * cells + b; };

    vector<int> cur, nxt;
    cur.reserve(3000);
    nxt.reserve(3000);

    int k0 = keyOf(a0, b0);
    seen[k0] = stamp;
    cur.push_back(k0);

    int steps = (L - 1) / 2;
    for (int step = 0; step < steps; step++) {
        nxt.clear();
        for (int key : cur) {
            int a = key / cells;
            int b = key - a * cells;

            int ax = gX[a], ay = gY[a];
            int bx = gX[b], by = gY[b];

            int aMoves[2], aCnt = 0;
            int bMoves[2], bCnt = 0;

            if (ax + 1 <= x2 - 1) aMoves[aCnt++] = gDown[a];
            if (ay + 1 <= y2 - 1) aMoves[aCnt++] = gRight[a];

            if (bx + 1 >= x1 - 1) bMoves[bCnt++] = gUp[b];
            if (by + 1 >= y1 - 1) bMoves[bCnt++] = gLeft[b];

            for (int i = 0; i < aCnt; i++) {
                int a2 = aMoves[i];
                int ax2 = gX[a2], ay2 = gY[a2];
                if (ax2 < x1 - 1 || ax2 > x2 - 1 || ay2 < y1 - 1 || ay2 > y2 - 1) continue;

                for (int j = 0; j < bCnt; j++) {
                    int b2 = bMoves[j];
                    int bx2 = gX[b2], by2 = gY[b2];
                    if (bx2 < x1 - 1 || bx2 > x2 - 1 || by2 < y1 - 1 || by2 > y2 - 1) continue;

                    if (ax2 > bx2 || ay2 > by2) continue;
                    if (rep.val[a2] != rep.val[b2]) continue;

                    int nk = keyOf(a2, b2);
                    if (seen[nk] == stamp) continue;
                    seen[nk] = stamp;
                    nxt.push_back(nk);
                }
            }
        }
        cur.swap(nxt);
        if (cur.empty()) return false;
    }

    if (L % 2 == 1) {
        for (int key : cur) {
            int a = key / cells;
            int b = key - a * cells;
            if (a == b) return true;
        }
        return false;
    } else {
        for (int key : cur) {
            int a = key / cells;
            int b = key - a * cells;
            int ax = gX[a], ay = gY[a];
            int bx = gX[b], by = gY[b];
            int md = abs(ax - bx) + abs(ay - by);
            if (md == 1 && ax <= bx && ay <= by) return true;
        }
        return false;
    }
}

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

    int n = inf.readInt(3, 49, "n");
    if (n % 2 == 0) finish(_pe, "n must be odd");
    gN = n;
    gCells = n * n;

    query_limit = 1LL * n * n;

    
    gX.assign(gCells, 0);
    gY.assign(gCells, 0);
    gDown.assign(gCells, -1);
    gRight.assign(gCells, -1);
    gUp.assign(gCells, -1);
    gLeft.assign(gCells, -1);
    for (int x = 0; x < n; x++) {
        for (int y = 0; y < n; y++) {
            int id = idx0(x, y);
            gX[id] = x;
            gY[id] = y;
            if (x + 1 < n) gDown[id] = idx0(x + 1, y);
            if (y + 1 < n) gRight[id] = idx0(x, y + 1);
            if (x - 1 >= 0) gUp[id] = idx0(x - 1, y);
            if (y - 1 >= 0) gLeft[id] = idx0(x, y - 1);
        }
    }

    
    bool hasFixedGrid = false;
    GridRep hidden;

    if (!inf.seekEof()) {
        vector<string> rows(n);
        for (int i = 0; i < n; i++) {
            rows[i] = inf.readToken();
            if ((int)rows[i].size() != n) finish(_pe, "invalid grid row length in inf");
            for (char c : rows[i]) if (c != '0' && c != '1') finish(_pe, "invalid grid char in inf");
        }
        if (rows[0][0] != '1') finish(_pe, "inf grid: top-left must be 1");
        if (rows[n - 1][n - 1] != '0') finish(_pe, "inf grid: bottom-right must be 0");
        hidden = buildRepFromRows(rows);
        hasFixedGrid = true;
    }

    vector<GridRep> candidates;
    if (!hasFixedGrid) {
        candidates.reserve(3);
        for (int which = 0; which < 3; which++) {
            auto rows = genCandidateRows(n, which);
            candidates.push_back(buildRepFromRows(rows));
        }
    }

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

    
    log_metrics();

    vector<int> seen((size_t)gCells * (size_t)gCells, 0);
    int stamp = 0;

    bool chosen = hasFixedGrid;
    int chosenCand = -1;

    auto sendInvalidAndDie = [&](const string& why) -> void {
        cout << -1 << "\n";
        cout.flush();
        finish(_pe, why);
    };

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

    while (true) {
        string cmd;
        if (!(cin >> cmd)) finish(_pe, "unexpected EOF from contestant");

        if (cmd == "?") {
            string sx1, sy1, sx2, sy2;
            if (!(cin >> sx1 >> sy1 >> sx2 >> sy2)) finish(_pe, "unexpected EOF in query arguments");
            long long X1, Y1, X2, Y2;
            if (!parseLLStrict(sx1, X1) || !parseLLStrict(sy1, Y1) || !parseLLStrict(sx2, X2) || !parseLLStrict(sy2, Y2))
                sendInvalidAndDie("non-integer query arguments");

            if (X1 < 1 || X1 > n || X2 < 1 || X2 > n || Y1 < 1 || Y1 > n || Y2 < 1 || Y2 > n)
                sendInvalidAndDie("query coordinates out of range");
            if (X1 > X2 || Y1 > Y2) sendInvalidAndDie("query order invalid");
            if (X1 + Y1 + 2 > X2 + Y2) sendInvalidAndDie("query cells adjacent or unreachable");

            queries++;
            if (queries > hard_cap) sendInvalidAndDie("too many queries (hard cap exceeded)");

            int x1 = (int)X1, y1 = (int)Y1, x2 = (int)X2, y2 = (int)Y2;
            int ans = 0;

            if (!chosen) {
                
                
                int cnt0 = 0, cnt1 = 0;
                int a0 = -1, a1 = -1;
                for (int i = 0; i < (int)candidates.size(); i++) {
                    bool r = palExists(candidates[i], x1, y1, x2, y2, seen, stamp);
                    if (!r) {
                        cnt0++;
                        if (a0 == -1) a0 = i;
                    } else {
                        cnt1++;
                        if (a1 == -1) a1 = i;
                    }
                }
                int pickAns;
                int pickIdx;
                if (cnt0 > cnt1) {
                    pickAns = 0; pickIdx = a0;
                } else if (cnt1 > cnt0) {
                    pickAns = 1; pickIdx = a1;
                } else {
                    
                    if (cnt0 > 0) { pickAns = 0; pickIdx = a0; }
                    else { pickAns = 1; pickIdx = a1; }
                }
                if (pickIdx < 0) finish(_pe, "internal: no candidate to pick");
                chosen = true;
                chosenCand = pickIdx;
                hidden = candidates[pickIdx];
                ans = pickAns;
            } else {
                ans = palExists(hidden, x1, y1, x2, y2, seen, stamp) ? 1 : 0;
            }

            cout << ans << "\n";
            cout.flush();
        } else if (cmd == "!") {
            vector<string> outRows(n);
            for (int i = 0; i < n; i++) {
                if (!(cin >> outRows[i])) finish(_pe, "unexpected EOF reading final grid");
                if ((int)outRows[i].size() != n) finish(_pe, "final grid row has wrong length");
                for (char c : outRows[i]) if (c != '0' && c != '1') finish(_pe, "final grid row has non-binary char");
            }

            if (!chosen) {
                
                if (hasFixedGrid) {
                    
                } else {
                    chosen = true;
                    chosenCand = 0;
                    hidden = candidates[0];
                }
            }

            if (outRows[0][0] != '1' || outRows[n - 1][n - 1] != '0') {
                finish(_wa, "final grid violates fixed corners");
            }

            if (outRows == hidden.rows) {
                finish(_ok, "correct");
            } else {
                finish(_wa, "wrong grid");
            }
        } else {
            sendInvalidAndDie("unknown command token");
        }
    }
}


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

static int clampInt(int x, int lo, int hi) {
    if (x < lo) return lo;
    if (x > hi) return hi;
    return x;
}

static int makeOdd(int n) {
    if (n % 2 == 0) n++;
    return n;
}

static vector<string> genGridNon(int n, long long seedVal) {
    vector<string> g(n, string(n, '0'));

    if (seedVal == 1) {
        
        
        g = {"101", "010", "000"};
        g[0][0] = '1';
        g[n - 1][n - 1] = '0';
        return g;
    }

    if (seedVal == 2) {
        
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int b = ((i + j) & 1);                 
                if (i % 7 == 0) b ^= 1;
                if (j % 11 == 0) b ^= 1;
                if (((i - j + n) % 9) == 0) b ^= 1;
                if (i == j) b ^= 1;
                if (i + j == n - 1) b ^= 1;
                if (i == n / 2 || j == n / 2) b ^= ((i + 2 * j) % 3 == 0);

                int r = rnd.next(0, 99);
                if (r < 18) b ^= 1;                    

                g[i][j] = char('0' + b);
            }
        }
        g[0][0] = '1';
        g[n - 1][n - 1] = '0';
        return g;
    }

    if (seedVal == 3) {
        
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int parity = ((i + j) & 1);
                int b;
                if (parity == 0) b = (rnd.next(0, 99) < 92 ? 1 : 0);
                else b = (rnd.next(0, 99) < 8 ? 1 : 0);

                if ((i % 5 == 0 && j % 5 == 0) || (i % 8 == 1 && j % 8 == 6)) b ^= 1;
                if (i == j || i + j == n - 1) b ^= 1;
                if (i == n / 2 || j == n / 2) b ^= ((i + j) % 3 == 1);

                int r = rnd.next(0, 99);
                if (r < 10) b ^= 1;

                g[i][j] = char('0' + b);
            }
        }
        g[0][0] = '1';
        g[n - 1][n - 1] = '0';
        return g;
    }

    
    int biasEven = opt<int>("biasEven", 86); 
    int biasOdd = opt<int>("biasOdd", 14);   
    int noise = opt<int>("noise", 16);       
    biasEven = clampInt(biasEven, 0, 100);
    biasOdd = clampInt(biasOdd, 0, 100);
    noise = clampInt(noise, 0, 60);

    int cx = n / 2, cy = n / 2;
    int rad = max(1, n / 6);

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            int parity = ((i + j) & 1);
            int b = 0;

            int pr = rnd.next(0, 99);
            if (parity == 0) b = (pr < biasEven ? 1 : 0);
            else b = (pr < biasOdd ? 1 : 0);

            
            
            
            
            if (i == j) b ^= 1;
            if (i + j == n - 1) b ^= 1;
            if (i == cx || j == cy) b ^= ((i + 2 * j) % 3 == 0);
            if ((i % 9 == 0) || (j % 10 == 0)) b ^= 1;
            if (((i * 7 + j * 13) % 17) == 0) b ^= 1;

            
            if (abs(i - cx) + abs(j - cy) <= rad) b ^= (((i + j) % 4) == 1);

            
            int rr = rnd.next(0, 99);
            if (rr < noise) b ^= 1;

            g[i][j] = char('0' + b);
        }
    }

    
    g[0][0] = '1';
    g[n - 1][n - 1] = '0';

    
    int oddOnes = 0, oddCnt = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (((i + j) & 1) == 1) {
                oddCnt++;
                oddOnes += (g[i][j] == '1');
            }
        }
    }
    if (oddOnes == 0 || oddOnes == oddCnt) {
        
        for (int t = 0; t < min(7, oddCnt); t++) {
            int i = (t * 7 + 3) % n;
            int j = (t * 11 + 5) % n;
            if (((i + j) & 1) == 0) j = (j + 1) % n;
            if (i == 0 && j == 0) j = 1;
            if (i == n - 1 && j == n - 1) j = n - 2;
            g[i][j] = (g[i][j] == '1' ? '0' : '1');
        }
        g[0][0] = '1';
        g[n - 1][n - 1] = '0';
    }

    return g;
}

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

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

    int nOpt = opt<int>("n", 0);
    int n = 0;

    if (nOpt != 0) {
        n = clampInt(nOpt, 3, 49);
        n = makeOdd(n);
        if (n >= 50) n = 49;
    } else {
        if (seedVal == 1) n = 3;
        else if (seedVal == 2) n = 49;
        else if (seedVal == 3) n = 49;
        else {
            
            int lo = opt<int>("nlo", 41);
            int hi = opt<int>("nhi", 49);
            lo = clampInt(lo, 3, 49);
            hi = clampInt(hi, 3, 49);
            if (lo > hi) swap(lo, hi);
            n = rnd.next(lo, hi);
            if (n % 2 == 0) n = (n == hi ? n - 1 : n + 1);
            if (n < 3) n = 3;
            if (n >= 50) n = 49;
            if (n % 2 == 0) n = 49;
        }
    }

    if (mode == "non") {
        vector<string> g = genGridNon(n, seedVal);
        cout << n << "\n";
        for (int i = 0; i < n; i++) cout << g[i] << "\n";
        return 0;
    }

    if (mode == "adp") {
        
        cout << n << "\n";
        return 0;
    }

    
    vector<string> g = genGridNon(n, seedVal);
    cout << n << "\n";
    for (int i = 0; i < n; i++) cout << g[i] << "\n";
    return 0;
}