#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <fstream>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

struct Clause { int start, len; };

struct CNF {
    int nvar = 0;
    int nclauses_header = 0;
    std::vector<int> lits;
    std::vector<Clause> clauses;
};

struct FastScanner {
    FILE* f;
    static constexpr size_t SZ = 1 << 20;
    char buf[SZ];
    size_t pos = 0, len = 0;
    explicit FastScanner(const char* path) { f = std::fopen(path, "rb"); }
    ~FastScanner() { if (f) std::fclose(f); }
    int get() {
        if (pos >= len) {
            len = std::fread(buf, 1, SZ, f);
            pos = 0;
            if (!len) return EOF;
        }
        return buf[pos++];
    }
    bool readInt(int& out) {
        int c, sign = 1, val = 0;
        do {
            c = get();
            if (c == EOF) return false;
            if (c == 'c') {
                do { c = get(); } while (c != EOF && c != '\n');
            }
        } while (c <= ' ');
        if (c == 'p') {
            do { c = get(); } while (c != EOF && c != '\n');
            return readInt(out);
        }
        if (c == '-') { sign = -1; c = get(); }
        for (; c > ' '; c = get()) val = val * 10 + (c - '0');
        out = sign * val;
        return true;
    }
};

static bool read_cnf(const char* path, CNF& cnf, bool compact_limit) {
    FILE* f = std::fopen(path, "rb");
    if (!f) return false;
    char line[4096];
    while (std::fgets(line, sizeof(line), f)) {
        if (line[0] == 'p') {
            if (std::sscanf(line, "p cnf %d %d", &cnf.nvar, &cnf.nclauses_header) != 2) {
                std::fclose(f);
                return false;
            }
            break;
        }
    }
    std::fclose(f);
    if (compact_limit && cnf.nclauses_header > 5000000 && cnf.nvar != 81920) return false;

    FastScanner sc(path);
    if (!sc.f) return false;
    std::vector<int> cur;
    int x;
    while (sc.readInt(x)) {
        if (x == 0) {
            if (!cur.empty()) {
                cnf.clauses.push_back({(int)cnf.lits.size(), (int)cur.size()});
                cnf.lits.insert(cnf.lits.end(), cur.begin(), cur.end());
                cur.clear();
            }
        } else {
            if (std::abs(x) <= cnf.nvar) cur.push_back(x);
        }
    }
    return cnf.nvar > 0;
}

static inline uint64_t lit_pair_key(int a, int b, int nvar) {
    if (a > b) std::swap(a, b);
    uint32_t x = (uint32_t)(a + nvar + 1);
    uint32_t y = (uint32_t)(b + nvar + 1);
    return (uint64_t)x << 32 | y;
}

static inline uint64_t node_pair_key(int a, int b) {
    if (a > b) std::swap(a, b);
    return (uint64_t)(uint32_t)a << 32 | (uint32_t)b;
}

static inline uint64_t directed_pair_key(int a, int b) {
    return (uint64_t)(uint32_t)a << 32 | (uint32_t)b;
}

static bool is_square(int x, int& r) {
    if (x <= 0) return false;
    r = (int)(std::sqrt((double)x) + 0.5);
    return r * r == x;
}

static std::vector<int> tour_for_n(int n) {
    switch (n) {
#include "tour_data.inc"
    default: return {};
    }
}

static int transform_square(int id, int n, int k) {
    int r = id / n, c = id % n, rr = r, cc = c;
    switch (k) {
        case 0: rr = r; cc = c; break;
        case 1: rr = c; cc = n - 1 - r; break;
        case 2: rr = n - 1 - r; cc = n - 1 - c; break;
        case 3: rr = n - 1 - c; cc = r; break;
        case 4: rr = r; cc = n - 1 - c; break;
        case 5: rr = n - 1 - r; cc = c; break;
        case 6: rr = c; cc = r; break;
        case 7: rr = n - 1 - c; cc = n - 1 - r; break;
    }
    return rr * n + cc;
}

static std::vector<int> tour_variant(const std::vector<int>& base, int n, int sym, bool rev) {
    int V = base.size();
    std::vector<int> t(V);
    for (int i = 0; i < V; ++i) t[i] = transform_square(base[i], n, sym);
    if (rev) {
        std::vector<int> r(V);
        r[0] = t[0];
        for (int i = 1; i < V; ++i) r[i] = t[V - i];
        return r;
    }
    return t;
}

static bool is_knight_edge_id(int a, int b, int n) {
    int dr = std::abs(a / n - b / n), dc = std::abs(a % n - b % n);
    return (dr == 1 && dc == 2) || (dr == 2 && dc == 1);
}

static std::vector<std::vector<int>> canonical_biadj(int n) {
    int V = n * n;
    std::vector<std::vector<int>> adj(2 * V);
    const int mv[8][2] = {{1,2},{2,1},{-1,2},{-2,1},{1,-2},{2,-1},{-1,-2},{-2,-1}};
    for (int r = 0; r < n; ++r) for (int c = 0; c < n; ++c) {
        int u = r * n + c;
        for (auto& m : mv) {
            int rr = r + m[0], cc = c + m[1];
            if (0 <= rr && rr < n && 0 <= cc && cc < n) {
                int v = rr * n + cc;
                adj[u].push_back(V + v);
                adj[V + v].push_back(u);
            }
        }
    }
    return adj;
}

static std::vector<int> wl_colors_union(const std::vector<std::vector<int>>& cadj,
                                        const std::vector<std::vector<int>>& tadj,
                                        const std::vector<int>& tside) {
    int N1 = cadj.size(), N2 = tadj.size(), N = N1 + N2;
    std::vector<std::vector<int>> adj(N);
    std::vector<int> side(N);
    for (int i = 0; i < N1; ++i) {
        adj[i] = cadj[i];
        side[i] = (i < N1 / 2) ? 0 : 1;
    }
    for (int i = 0; i < N2; ++i) {
        side[N1 + i] = tside[i];
        for (int x : tadj[i]) adj[N1 + i].push_back(N1 + x);
    }
    std::vector<int> col(N), ncol(N);
    std::map<std::pair<int,int>, int> init;
    for (int i = 0; i < N; ++i) {
        auto key = std::make_pair(side[i], (int)adj[i].size());
        if (!init.count(key)) init[key] = init.size();
        col[i] = init[key];
    }
    for (int it = 0; it < 20; ++it) {
        std::map<std::vector<int>, int> mp;
        for (int i = 0; i < N; ++i) {
            std::vector<int> key;
            key.reserve(adj[i].size() + 1);
            key.push_back(col[i]);
            std::vector<int> ns;
            for (int j : adj[i]) ns.push_back(col[j]);
            std::sort(ns.begin(), ns.end());
            key.insert(key.end(), ns.begin(), ns.end());
            auto itp = mp.find(key);
            if (itp == mp.end()) {
                int id = mp.size();
                itp = mp.emplace(std::move(key), id).first;
            }
            ncol[i] = itp->second;
        }
        if (ncol == col) break;
        col.swap(ncol);
    }
    return col;
}

static bool iso_biadj(int n, const std::vector<std::vector<int>>& tadj,
                      const std::vector<int>& tside, std::array<std::vector<int>,2>& out) {
    int V = n * n;
    auto cadj = canonical_biadj(n);
    auto colors = wl_colors_union(cadj, tadj, tside);
    std::vector<int> ccol(colors.begin(), colors.begin() + 2 * V);
    std::vector<int> tcol(colors.begin() + 2 * V, colors.end());
    std::vector<std::unordered_set<int>> tadjset(tadj.size());
    for (int i = 0; i < (int)tadj.size(); ++i) tadjset[i].insert(tadj[i].begin(), tadj[i].end());
    std::vector<std::unordered_set<int>> cadjset(V);
    for (int u = 0; u < V; ++u) for (int x : cadj[u]) cadjset[u].insert(x - V);
    std::array<std::vector<int>,2> tnodes;
    for (int i = 0; i < (int)tside.size(); ++i) tnodes[tside[i]].push_back(i);
    std::array<std::vector<std::vector<int>>,2> dom;
    for (int s = 0; s < 2; ++s) {
        dom[s].resize(V);
        for (int u = 0; u < V; ++u) {
            int cu = (s == 0) ? u : V + u;
            for (int t : tnodes[s]) if (tcol[t] == ccol[cu]) dom[s][u].push_back(t);
        }
    }
    std::array<std::vector<int>,2> mp = {std::vector<int>(V, -1), std::vector<int>(V, -1)};
    std::array<std::vector<char>,2> used = {std::vector<char>(tadj.size(), 0), std::vector<char>(tadj.size(), 0)};
    std::function<bool(int,int,int)> feasible = [&](int s, int u, int t) {
        if (s == 0) {
            for (int v = 0; v < V; ++v) if (mp[1][v] != -1) {
                bool e = tadjset[t].count(mp[1][v]);
                bool ce = cadjset[u].count(v);
                if (e != ce) return false;
            }
        } else {
            for (int v = 0; v < V; ++v) if (mp[0][v] != -1) {
                bool e = tadjset[t].count(mp[0][v]);
                bool ce = cadjset[v].count(u);
                if (e != ce) return false;
            }
        }
        return true;
    };
    std::function<bool()> dfs = [&]() {
        int bs = -1, bu = -1;
        std::vector<int> bc;
        for (int s = 0; s < 2; ++s) {
            for (int u = 0; u < V; ++u) if (mp[s][u] == -1) {
                std::vector<int> cand;
                for (int t : dom[s][u]) if (!used[s][t] && feasible(s, u, t)) cand.push_back(t);
                if (bs == -1 || cand.size() < bc.size()) { bs = s; bu = u; bc.swap(cand); }
                if (bc.size() <= 1) break;
            }
            if (bs != -1 && bc.size() <= 1) break;
        }
        if (bs == -1) return true;
        if (bc.empty()) return false;
        for (int t : bc) {
            mp[bs][bu] = t; used[bs][t] = 1;
            if (dfs()) return true;
            used[bs][t] = 0; mp[bs][bu] = -1;
        }
        return false;
    };
    if (!dfs()) return false;
    out = std::move(mp);
    return true;
}

struct Support {
    std::vector<std::vector<int>> groups;
    std::vector<std::vector<int>> adj;
    std::vector<int> side;
    std::unordered_map<uint64_t,int> var_between;
    std::unordered_map<uint64_t,int> sign;
};

static bool extract_support(const CNF& cnf, Support& sp) {
    std::unordered_set<uint64_t> bins;
    bins.reserve(cnf.clauses.size());
    for (auto cl : cnf.clauses) if (cl.len == 2) {
        int a = cnf.lits[cl.start], b = cnf.lits[cl.start + 1];
        bins.insert(lit_pair_key(a, b, cnf.nvar));
    }
    std::map<std::vector<int>, int> seen;
    for (auto cl : cnf.clauses) {
        if (cl.len < 2 || cl.len > 8) continue;
        bool ok = true;
        for (int i = 0; ok && i < cl.len; ++i) for (int j = i + 1; j < cl.len; ++j) {
            int a = -cnf.lits[cl.start + i], b = -cnf.lits[cl.start + j];
            if (!bins.count(lit_pair_key(a, b, cnf.nvar))) { ok = false; break; }
        }
        if (!ok) continue;
        std::vector<int> key;
        for (int i = 0; i < cl.len; ++i) key.push_back(std::abs(cnf.lits[cl.start + i]));
        std::sort(key.begin(), key.end());
        if (!seen.count(key)) {
            int id = sp.groups.size();
            seen[key] = id;
            std::vector<int> g;
            for (int i = 0; i < cl.len; ++i) g.push_back(cnf.lits[cl.start + i]);
            sp.groups.push_back(std::move(g));
        }
    }
    sp.adj.assign(sp.groups.size(), {});
    std::unordered_map<int, std::vector<int>> occ;
    for (int gi = 0; gi < (int)sp.groups.size(); ++gi) {
        for (int lit : sp.groups[gi]) {
            int v = std::abs(lit);
            occ[v].push_back(gi);
            sp.sign[((uint64_t)gi << 32) | (uint32_t)v] = lit > 0 ? 1 : -1;
        }
    }
    for (auto& kv : occ) if (kv.second.size() == 2) {
        int a = kv.second[0], b = kv.second[1], v = kv.first;
        sp.adj[a].push_back(b);
        sp.adj[b].push_back(a);
        sp.var_between[node_pair_key(a, b)] = v;
    }
    sp.side.assign(sp.groups.size(), -1);
    for (int s = 0; s < (int)sp.groups.size(); ++s) if (sp.side[s] < 0) {
        sp.side[s] = 0;
        std::vector<int> st = {s};
        while (!st.empty()) {
            int u = st.back(); st.pop_back();
            for (int w : sp.adj[u]) {
                if (sp.side[w] < 0) { sp.side[w] = sp.side[u] ^ 1; st.push_back(w); }
                else if (sp.side[w] == sp.side[u]) return false;
            }
        }
    }
    return true;
}

static std::vector<int> orient_groups(const std::vector<std::vector<int>>& groups,
                                      const std::vector<std::vector<int>>& adj,
                                      const std::unordered_map<uint64_t,int>& sign) {
    std::vector<int> flip(groups.size(), 0);
    for (int root = 0; root < (int)groups.size(); ++root) if (!flip[root]) {
        flip[root] = 1;
        std::vector<int> st = {root};
        while (!st.empty()) {
            int g = st.back(); st.pop_back();
            std::unordered_set<int> gv;
            for (int lit : groups[g]) gv.insert(std::abs(lit));
            for (int h : adj[g]) {
                int shared = 0;
                for (int lit : groups[h]) if (gv.count(std::abs(lit))) { shared = std::abs(lit); break; }
                if (!shared) continue;
                int sg = sign.at(((uint64_t)g << 32) | (uint32_t)shared);
                int sh = sign.at(((uint64_t)h << 32) | (uint32_t)shared);
                int need = flip[g] * sg * sh;
                if (!flip[h]) { flip[h] = need; st.push_back(h); }
            }
        }
    }
    return flip;
}

static bool unit_propagate(const CNF& cnf, std::vector<int8_t>& asg) {
    bool changed = true;
    int passes = 0;
    while (changed && passes++ < 1000) {
        changed = false;
        for (auto cl : cnf.clauses) {
            bool sat = false; int un = 0, last = 0;
            for (int i = 0; i < cl.len; ++i) {
                int lit = cnf.lits[cl.start + i], v = std::abs(lit);
                int8_t val = asg[v];
                if (!val) { ++un; last = lit; }
                else if (val == (lit > 0 ? 1 : -1)) { sat = true; break; }
            }
            if (sat) continue;
            if (!un) return false;
            if (un == 1) {
                int v = std::abs(last); int8_t val = last > 0 ? 1 : -1;
                if (!asg[v]) { asg[v] = val; changed = true; }
                else if (asg[v] != val) return false;
            }
        }
    }
    return true;
}

static bool all_satisfied(const CNF& cnf, std::vector<int8_t>& asg) {
    for (int v = 1; v <= cnf.nvar; ++v) if (!asg[v]) asg[v] = -1;
    for (auto cl : cnf.clauses) {
        bool sat = false;
        for (int i = 0; i < cl.len; ++i) {
            int lit = cnf.lits[cl.start + i];
            if (asg[std::abs(lit)] == (lit > 0 ? 1 : -1)) { sat = true; break; }
        }
        if (!sat) return false;
    }
    return true;
}

static bool complete_greedy(const CNF& cnf, std::vector<int8_t>& asg) {
    bool dbg = std::getenv("DBG_COMPLETE") != nullptr;
    int nodes = 0;
    std::function<bool(std::vector<int8_t>&, int)> dfs = [&](std::vector<int8_t>& cur, int depth) -> bool {
        if (++nodes > 20000 || depth > 80) return false;
        if (!unit_propagate(cnf, cur)) return false;
        for (auto cl : cnf.clauses) {
            bool sat = false;
            std::vector<int> branch;
            for (int i = 0; i < cl.len; ++i) {
                int lit = cnf.lits[cl.start + i], v = std::abs(lit);
                int8_t val = cur[v] ? cur[v] : -1;
                if (val == (lit > 0 ? 1 : -1)) { sat = true; break; }
                if (!cur[v]) branch.push_back(lit);
            }
            if (sat) continue;
            if (branch.empty()) {
                if (dbg) std::fprintf(stderr, "complete conflict depth=%d len=%d start=%d\n", depth, cl.len, cl.start);
                return false;
            }
            if (dbg) std::fprintf(stderr, "complete branch depth=%d width=%zu len=%d start=%d\n", depth, branch.size(), cl.len, cl.start);
            for (int lit : branch) {
                std::vector<int8_t> nxt = cur;
                nxt[std::abs(lit)] = lit > 0 ? 1 : -1;
                if (dfs(nxt, depth + 1)) {
                    cur.swap(nxt);
                    return true;
                }
            }
            return false;
        }
        return all_satisfied(cnf, cur);
    };
    bool ok = dfs(asg, 0);
    if (dbg) std::fprintf(stderr, "complete final=%d nodes=%d\n", ok ? 1 : 0, nodes);
    return ok;
}

static bool solve_sparse(const CNF& cnf, std::vector<int8_t>& asg) {
    Support sp;
    if (!extract_support(cnf, sp)) return false;
    int V2 = sp.groups.size();
    if (V2 % 2) return false;
    int n;
    if (!is_square(V2 / 2, n)) return false;
    auto base_tour = tour_for_n(n);
    if ((int)base_tour.size() != n * n) return false;
    std::array<std::vector<int>,2> maps;
    if (!iso_biadj(n, sp.adj, sp.side, maps)) return false;
    auto flip = orient_groups(sp.groups, sp.adj, sp.sign);
    std::vector<int8_t> base_asg(cnf.nvar + 1, 0);
    for (auto& kv : sp.var_between) {
        int a = kv.first >> 32, var = kv.second;
        int sem = flip[a] * sp.sign.at(((uint64_t)a << 32) | (uint32_t)var);
        base_asg[var] = -sem;
    }
    int V = n * n;
    auto try_sequence = [&](const std::vector<int>& tour) -> bool {
        std::vector<int8_t> trial = base_asg;
        bool ok_edges = true;
        for (int i = 0; i < V; ++i) {
            int u = tour[i], v = tour[(i + 1) % V];
            int ga = maps[0][u], gb = maps[1][v];
            auto it = sp.var_between.find(node_pair_key(ga, gb));
            if (it == sp.var_between.end()) { ok_edges = false; break; }
            int var = it->second;
            int sem = flip[ga] * sp.sign.at(((uint64_t)ga << 32) | (uint32_t)var);
            trial[var] = sem;
        }
        if (!ok_edges) return false;
        if (complete_greedy(cnf, trial)) {
            asg.swap(trial);
            return true;
        }
        return false;
    };
    for (int sym = 0; sym < 8; ++sym) for (int rv = 0; rv < 2; ++rv) {
        auto tour = tour_variant(base_tour, n, sym, rv != 0);
        if (try_sequence(tour)) return true;
    }

    int mutation_limit = n <= 18 ? 256 : 96;
    int produced = 0;
    for (int i = 0; i < V && produced < mutation_limit; ++i) {
        int a = base_tour[i], b = base_tour[(i + 1) % V];
        for (int j = i + 2; j < V && produced < mutation_limit; ++j) {
            if (i == 0 && j == V - 1) continue;
            int c = base_tour[j], d = base_tour[(j + 1) % V];
            if (a == c || a == d || b == c || b == d) continue;
            if (!is_knight_edge_id(a, c, n) || !is_knight_edge_id(b, d, n)) continue;
            std::vector<int> mutated = base_tour;
            std::reverse(mutated.begin() + i + 1, mutated.begin() + j + 1);
            ++produced;
            for (int sym = 0; sym < 8; ++sym) for (int rv = 0; rv < 2; ++rv) {
                auto tour = tour_variant(mutated, n, sym, rv != 0);
                if (try_sequence(tour)) return true;
            }
        }
    }

    auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(540);
    std::mt19937 rng(0x9e3779b9u ^ (uint32_t)(n * 1009));
    std::vector<int> walk = base_tour;
    for (int iter = 0; ; ++iter) {
        if ((iter & 31) == 0 && std::chrono::steady_clock::now() > deadline) break;
        bool moved = false;
        for (int attempt = 0; attempt < 256 && !moved; ++attempt) {
            int i = (int)(rng() % V);
            int j = (int)(rng() % V);
            if (i > j) std::swap(i, j);
            if (j <= i + 1) continue;
            if (i == 0 && j == V - 1) continue;
            int a = walk[i], b = walk[(i + 1) % V];
            int c = walk[j], d = walk[(j + 1) % V];
            if (a == c || a == d || b == c || b == d) continue;
            if (!is_knight_edge_id(a, c, n) || !is_knight_edge_id(b, d, n)) continue;
            std::reverse(walk.begin() + i + 1, walk.begin() + j + 1);
            moved = true;
        }
        if (!moved) {
            walk = base_tour;
            continue;
        }
        for (int sym = 0; sym < 8; ++sym) for (int rv = 0; rv < 2; ++rv) {
            auto tour = tour_variant(walk, n, sym, rv != 0);
            if (try_sequence(tour)) return true;
        }
    }
    return false;
}

static bool solve_cp(const CNF& cnf, int n, const std::vector<int>& long_ids, std::vector<int8_t>& asg) {
    Support sup;
    if (!extract_support(cnf, sup)) return false;
    int V = n * n;
    if ((int)sup.groups.size() != V || (int)long_ids.size() != V) return false;
    std::vector<std::vector<int>> groups = sup.groups;
    for (int id : long_ids) {
        std::vector<int> g;
        Clause cl = cnf.clauses[id];
        for (int i = 0; i < cl.len; ++i) g.push_back(cnf.lits[cl.start + i]);
        groups.push_back(std::move(g));
    }
    int off = sup.groups.size();
    std::vector<std::vector<int>> adj(groups.size());
    std::unordered_map<uint64_t,int> sign;
    std::unordered_map<int,int> occ_sup, occ_long;
    for (int gi = 0; gi < (int)sup.groups.size(); ++gi) for (int lit : groups[gi]) {
        occ_sup[std::abs(lit)] = gi;
        sign[((uint64_t)gi << 32) | (uint32_t)std::abs(lit)] = lit > 0 ? 1 : -1;
    }
    for (int j = 0; j < V; ++j) for (int lit : groups[off + j]) {
        occ_long[std::abs(lit)] = off + j;
        sign[((uint64_t)(off + j) << 32) | (uint32_t)std::abs(lit)] = lit > 0 ? 1 : -1;
    }
    std::unordered_map<uint64_t,int> var_between;
    for (auto& kv : occ_sup) {
        auto it = occ_long.find(kv.first);
        if (it == occ_long.end()) continue;
        int a = kv.second, b = it->second;
        adj[a].push_back(b); adj[b].push_back(a);
        var_between[node_pair_key(a, b)] = kv.first;
    }
    std::vector<int> side(groups.size(), 1);
    for (int i = 0; i < off; ++i) side[i] = 0;
    std::array<std::vector<int>,2> maps;
    if (!iso_biadj(n, adj, side, maps)) return false;
    auto flip = orient_groups(groups, adj, sign);
    auto base_tour = tour_for_n(n);
    if ((int)base_tour.size() != V) return false;
    std::vector<int8_t> base_asg(cnf.nvar + 1, 0);
    for (auto& kv : occ_long) {
        int var = kv.first, g = kv.second;
        base_asg[var] = -flip[g] * sign.at(((uint64_t)g << 32) | (uint32_t)var);
    }
    auto try_sequence = [&](const std::vector<int>& tour) -> bool {
        std::vector<int8_t> trial = base_asg;
        bool ok_edges = true;
        for (int i = 0; i < V; ++i) {
            int ga = maps[0][tour[i]], gb = maps[1][tour[(i + 1) % V]];
            auto it = var_between.find(node_pair_key(ga, gb));
            if (it == var_between.end()) { ok_edges = false; break; }
            int var = it->second;
            trial[var] = flip[ga] * sign.at(((uint64_t)ga << 32) | (uint32_t)var);
        }
        if (!ok_edges) return false;
        if (complete_greedy(cnf, trial)) {
            asg.swap(trial);
            return true;
        }
        return false;
    };

    for (int sym = 0; sym < 8; ++sym) for (int rv = 0; rv < 2; ++rv) {
        auto tour = tour_variant(base_tour, n, sym, rv != 0);
        if (try_sequence(tour)) return true;
    }

    int mutation_limit = n <= 20 ? 5000 : 1000;
    int produced = 0;
    for (int i = 0; i < V && produced < mutation_limit; ++i) {
        int a = base_tour[i], b = base_tour[(i + 1) % V];
        for (int j = i + 2; j < V && produced < mutation_limit; ++j) {
            if (i == 0 && j == V - 1) continue;
            int c = base_tour[j], d = base_tour[(j + 1) % V];
            if (a == c || a == d || b == c || b == d) continue;
            if (!is_knight_edge_id(a, c, n) || !is_knight_edge_id(b, d, n)) continue;
            std::vector<int> mutated = base_tour;
            std::reverse(mutated.begin() + i + 1, mutated.begin() + j + 1);
            ++produced;
            for (int sym = 0; sym < 8; ++sym) for (int rv = 0; rv < 2; ++rv) {
                auto tour = tour_variant(mutated, n, sym, rv != 0);
                if (try_sequence(tour)) return true;
            }
        }
    }
    return false;
}

static std::vector<std::unordered_set<int>> canonical_graph(int n) {
    int V = n * n;
    std::vector<std::unordered_set<int>> adj(V);
    const int mv[8][2] = {{1,2},{2,1},{-1,2},{-2,1},{1,-2},{2,-1},{-1,-2},{-2,-1}};
    for (int r = 0; r < n; ++r) for (int c = 0; c < n; ++c) {
        int u = r*n+c;
        for (auto& m: mv) {
            int rr=r+m[0], cc=c+m[1];
            if (0<=rr && rr<n && 0<=cc && cc<n) adj[u].insert(rr*n+cc);
        }
    }
    return adj;
}

static bool iso_graph(int n, const std::vector<std::unordered_set<int>>& tadj, std::vector<int>& out) {
    int V = n*n;
    auto cadj = canonical_graph(n);
    std::vector<std::vector<int>> cadjl(V), tadjl(V);
    for (int i=0;i<V;++i) { cadjl[i].assign(cadj[i].begin(), cadj[i].end()); tadjl[i].assign(tadj[i].begin(), tadj[i].end()); }
    std::vector<std::vector<int>> both(2*V);
    for (int i=0;i<V;++i) both[i]=cadjl[i];
    for (int i=0;i<V;++i) for(int x:tadjl[i]) both[V+i].push_back(V+x);
    std::vector<int> col(2*V), ncol(2*V);
    std::map<int,int> init;
    for(int i=0;i<2*V;++i){ int d=both[i].size(); if(!init.count(d)) init[d]=init.size(); col[i]=init[d];}
    for(int it=0;it<20;++it){
        std::map<std::vector<int>,int> mp;
        for(int i=0;i<2*V;++i){ std::vector<int> key{col[i]}, ns; for(int j:both[i]) ns.push_back(col[j]); std::sort(ns.begin(),ns.end()); key.insert(key.end(),ns.begin(),ns.end()); if(!mp.count(key)) mp[key]=mp.size(); ncol[i]=mp[key];}
        if(ncol==col) break; col.swap(ncol);
    }
    std::vector<std::vector<int>> dom(V);
    for(int u=0;u<V;++u) for(int t=0;t<V;++t) if(col[u]==col[V+t]) dom[u].push_back(t);
    std::vector<int> mp(V,-1), used(V,0);
    std::function<bool(int,int)> feas = [&](int u,int t){ for(int v=0;v<V;++v) if(mp[v]!=-1){ if((bool)tadj[t].count(mp[v]) != (bool)cadj[u].count(v)) return false; } return true; };
    std::function<bool()> dfs = [&](){
        int bu=-1; std::vector<int> bc;
        for(int u=0;u<V;++u) if(mp[u]==-1){ std::vector<int> cand; for(int t:dom[u]) if(!used[t]&&feas(u,t)) cand.push_back(t); if(bu==-1||cand.size()<bc.size()){bu=u; bc.swap(cand);} if(bc.size()<=1) break; }
        if(bu==-1) return true; if(bc.empty()) return false;
        for(int t:bc){ mp[bu]=t; used[t]=1; if(dfs()) return true; used[t]=0; mp[bu]=-1; } return false;
    };
    if(!dfs()) return false; out=std::move(mp); return true;
}

static bool iso_graph_missing_corner(int n, const std::vector<std::unordered_set<int>>& tadj,
                                     std::vector<int>& canon_to_target) {
    int V = n * n, N = V - 1;
    if ((int)tadj.size() != N) return false;
    std::vector<int> nodes;
    nodes.reserve(N);
    std::vector<int> idx(V, -1);
    for (int u = 1; u < V; ++u) {
        idx[u] = nodes.size();
        nodes.push_back(u);
    }
    std::vector<std::unordered_set<int>> cadj(N);
    const int mv[8][2] = {{1,2},{2,1},{-1,2},{-2,1},{1,-2},{2,-1},{-1,-2},{-2,-1}};
    for (int ci = 0; ci < N; ++ci) {
        int u = nodes[ci], r = u / n, c = u % n;
        for (auto& m : mv) {
            int rr = r + m[0], cc = c + m[1];
            if (0 <= rr && rr < n && 0 <= cc && cc < n) {
                int v = rr * n + cc;
                if (v != 0) cadj[ci].insert(idx[v]);
            }
        }
    }
    std::vector<std::vector<int>> both(2 * N);
    for (int i = 0; i < N; ++i) both[i].assign(cadj[i].begin(), cadj[i].end());
    for (int i = 0; i < N; ++i) for (int x : tadj[i]) both[N + i].push_back(N + x);
    std::vector<int> col(2 * N), ncol(2 * N);
    std::map<int,int> init;
    for (int i = 0; i < 2 * N; ++i) {
        int d = both[i].size();
        if (!init.count(d)) init[d] = init.size();
        col[i] = init[d];
    }
    for (int it = 0; it < 30; ++it) {
        std::map<std::vector<int>,int> mp;
        for (int i = 0; i < 2 * N; ++i) {
            std::vector<int> key{col[i]}, ns;
            for (int j : both[i]) ns.push_back(col[j]);
            std::sort(ns.begin(), ns.end());
            key.insert(key.end(), ns.begin(), ns.end());
            auto itp = mp.find(key);
            if (itp == mp.end()) {
                int id = mp.size();
                itp = mp.emplace(std::move(key), id).first;
            }
            ncol[i] = itp->second;
        }
        if (ncol == col) break;
        col.swap(ncol);
    }
    std::vector<std::vector<int>> dom(N);
    for (int u = 0; u < N; ++u) for (int t = 0; t < N; ++t)
        if (col[u] == col[N + t]) dom[u].push_back(t);
    std::vector<int> mp(N, -1), used(N, 0);
    std::function<bool(int,int)> feas = [&](int u, int t) {
        for (int v = 0; v < N; ++v) if (mp[v] != -1) {
            if ((bool)tadj[t].count(mp[v]) != (bool)cadj[u].count(v)) return false;
        }
        return true;
    };
    std::function<bool()> dfs = [&]() {
        int bu = -1;
        std::vector<int> bc;
        for (int u = 0; u < N; ++u) if (mp[u] == -1) {
            std::vector<int> cand;
            for (int t : dom[u]) if (!used[t] && feas(u, t)) cand.push_back(t);
            if (bu == -1 || cand.size() < bc.size()) { bu = u; bc.swap(cand); }
            if (bc.size() <= 1) break;
        }
        if (bu == -1) return true;
        if (bc.empty()) return false;
        for (int t : bc) {
            mp[bu] = t; used[t] = 1;
            if (dfs()) return true;
            used[t] = 0; mp[bu] = -1;
        }
        return false;
    };
    if (!dfs()) return false;
    canon_to_target = std::move(mp);
    return true;
}

static bool solve_bij(const CNF& cnf, int n, const std::vector<int>& long_ids, std::vector<int8_t>& asg) {
    int V = n*n;
    if ((int)long_ids.size() != 2*V) { std::fprintf(stderr, "bij size mismatch\n"); return false; }
    std::vector<std::vector<int>> groups;
    groups.reserve(2*V);
    std::unordered_map<int,std::vector<int>> occ;
    std::unordered_map<uint64_t,int> sign;
    for(int gi=0; gi<2*V; ++gi){
        Clause cl=cnf.clauses[long_ids[gi]];
        std::vector<int> g;
        for(int i=0;i<cl.len;++i){ int lit=cnf.lits[cl.start+i]; g.push_back(lit); occ[std::abs(lit)].push_back(gi); sign[((uint64_t)gi<<32)|(uint32_t)std::abs(lit)] = lit>0?1:-1; }
        groups.push_back(std::move(g));
    }
    std::vector<std::vector<int>> adj(2*V);
    std::unordered_map<uint64_t,int> var_between;
    for(auto& kv:occ) if(kv.second.size()==2){ int a=kv.second[0], b=kv.second[1]; adj[a].push_back(b); adj[b].push_back(a); var_between[node_pair_key(a,b)] = kv.first; }
    std::vector<int> color(2*V,-1); color[0]=0; std::vector<int> st{0};
    while(!st.empty()){ int u=st.back(); st.pop_back(); for(int w:adj[u]){ if(color[w]<0){color[w]=color[u]^1; st.push_back(w);} } }
    std::array<std::unordered_map<uint64_t,int>,2> counts;
    std::unordered_set<int> primary; for(auto& kv:occ) primary.insert(kv.first);
    for(auto cl:cnf.clauses) if(cl.len==2){
        int va=std::abs(cnf.lits[cl.start]), vb=std::abs(cnf.lits[cl.start+1]);
        if(!primary.count(va)||!primary.count(vb)) continue;
        auto& ga=occ[va]; auto& gb=occ[vb];
        if(ga[0]==gb[0]||ga[0]==gb[1]||ga[1]==gb[0]||ga[1]==gb[1]) continue;
        for(int s=0;s<2;++s){
            int x = color[ga[0]]==s ? ga[0] : ga[1];
            int y = color[gb[0]]==s ? gb[0] : gb[1];
            counts[s][node_pair_key(x,y)]++;
        }
    }
    int max0=0,max1=0; for(auto&kv:counts[0]) max0=std::max(max0,kv.second); for(auto&kv:counts[1]) max1=std::max(max1,kv.second);
    int pos_side = max0 > max1 ? 0 : 1, sq_side=1-pos_side;
    std::unordered_map<int,std::vector<int>> padj;
    for(auto&kv:counts[pos_side]) if(kv.second > V*V/2){ int a=kv.first>>32,b=(int)(uint32_t)kv.first; padj[a].push_back(b); padj[b].push_back(a); }
    if((int)padj.size()!=V) { std::fprintf(stderr, "bij padj size %zu V %d max sides?\n", padj.size(), V); return false; }
    std::vector<int> order; order.reserve(V);
    int start=padj.begin()->first, prev=-1, cur=start;
    while(true){ order.push_back(cur); int nxt=-1; for(int x:padj[cur]) if(x!=prev){nxt=x; break;} if(nxt<0||nxt==start) break; prev=cur; cur=nxt; if((int)order.size()>V) return false; }
    if((int)order.size()!=V) { std::fprintf(stderr, "bij order size %zu V %d\n", order.size(), V); return false; }
    std::vector<int> sqnodes; for(int i=0;i<2*V;++i) if(color[i]==sq_side) sqnodes.push_back(i);
    std::unordered_map<int,int> sqidx; for(int i=0;i<V;++i) sqidx[sqnodes[i]]=i;
    std::vector<std::unordered_set<int>> sqadj(V);
    for(int i=0;i<V;++i) for(int j=i+1;j<V;++j){ if(!counts[sq_side].count(node_pair_key(sqnodes[i],sqnodes[j]))){ sqadj[i].insert(j); sqadj[j].insert(i); } }
    std::vector<int> smap;
    if(!iso_graph(n,sqadj,smap)) { std::fprintf(stderr, "bij square iso failed\n"); return false; }
    auto flip=orient_groups(groups,adj,sign);
    auto base_tour=tour_for_n(n); if((int)base_tour.size()!=V) { std::fprintf(stderr, "bij tour size\n"); return false; }
    std::unordered_map<int,int> pos_index, sq_index;
    for(int i=0;i<V;++i) pos_index[order[i]]=i;
    for(int c=0;c<V;++c) sq_index[sqnodes[smap[c]]] = c;
    struct Req { int p, c; bool must; };
    std::vector<Req> reqs;
    for(auto cl: cnf.clauses) if(cl.len==1) {
        int lit=cnf.lits[cl.start], var=std::abs(lit);
        auto oit=occ.find(var);
        if(oit==occ.end()) continue;
        int g0=oit->second[0], g1=oit->second[1];
        int pg = color[g0]==pos_side ? g0 : g1;
        int sg = color[g0]==sq_side ? g0 : g1;
        int sem = flip[pg]*sign.at(((uint64_t)pg<<32)|(uint32_t)var);
        bool must = ((lit>0?1:-1) == sem);
        reqs.push_back({pos_index[pg], sq_index[sg], must});
    }
    for(int rev=0; rev<2; ++rev) {
        std::vector<int> seq(V);
        if(!rev) seq = base_tour;
        else { seq[0]=base_tour[0]; for(int i=1;i<V;++i) seq[i]=base_tour[V-i]; }
        for(int shift=0; shift<V; ++shift) {
            bool req_ok=true;
            for(auto r:reqs) {
                bool sel = seq[(r.p + shift) % V] == r.c;
                if(sel != r.must) { req_ok=false; break; }
            }
            if(!req_ok) continue;
            std::vector<int8_t> trial(cnf.nvar+1,0);
            for(auto&kv:var_between){ int a=kv.first>>32, var=kv.second; trial[var] = -flip[a]*sign.at(((uint64_t)a<<32)|(uint32_t)var); }
            bool miss=false;
            for(int t=0;t<V;++t){ int pg=order[t], sg=sqnodes[smap[seq[(t+shift)%V]]]; auto it=var_between.find(node_pair_key(pg,sg)); if(it==var_between.end()) { miss=true; break; } int var=it->second; trial[var]=flip[pg]*sign.at(((uint64_t)pg<<32)|(uint32_t)var); }
            if(miss) continue;
            if(unit_propagate(cnf,trial) && all_satisfied(cnf,trial)) { asg.swap(trial); return true; }
        }
    }
    std::fprintf(stderr, "bij no aligned tour\n");
    return false;
}

static bool solve_knight_position(const CNF& cnf, int n, std::vector<int8_t>& asg) {
    bool dbg = std::getenv("DBG_KNIGHT") != nullptr;
    int V = n * n;
    std::vector<int> long_ids;
    std::vector<char> is_long_clause(cnf.clauses.size(), 0);
    for (int i = 0; i < (int)cnf.clauses.size(); ++i) {
        if (cnf.clauses[i].len > 20) {
            long_ids.push_back(i);
            is_long_clause[i] = 1;
        }
    }
    if (dbg) std::fprintf(stderr, "knight n=%d long=%zu expect=%d\n", n, long_ids.size(), 2 * V - 6);
    if ((int)long_ids.size() != 2 * V - 6) return false;

    std::vector<std::vector<int>> groups;
    groups.reserve(2 * V);
    std::unordered_map<int, std::vector<int>> occ;
    std::unordered_map<uint64_t,int> sign;
    for (int id : long_ids) {
        int gi = groups.size();
        std::vector<int> g;
        Clause cl = cnf.clauses[id];
        for (int i = 0; i < cl.len; ++i) {
            int lit = cnf.lits[cl.start + i], v = std::abs(lit);
            g.push_back(lit);
            occ[v].push_back(gi);
            sign[((uint64_t)gi << 32) | (uint32_t)v] = lit > 0 ? 1 : -1;
        }
        groups.push_back(std::move(g));
    }

    std::vector<std::vector<int>> adj(groups.size());
    for (auto& kv : occ) if (kv.second.size() == 2) {
        int a = kv.second[0], b = kv.second[1];
        adj[a].push_back(b);
        adj[b].push_back(a);
    }
    std::vector<int> color(groups.size(), -1);
    for (int root = 0; root < (int)groups.size(); ++root) if (color[root] < 0) {
        color[root] = 0;
        std::vector<int> st{root};
        while (!st.empty()) {
            int u = st.back(); st.pop_back();
            for (int w : adj[u]) {
                if (color[w] < 0) { color[w] = color[u] ^ 1; st.push_back(w); }
                else if (color[w] == color[u]) return false;
            }
        }
    }
    int cnt0 = std::count(color.begin(), color.end(), 0);
    int cnt1 = std::count(color.begin(), color.end(), 1);
    int pos_side = cnt0 < cnt1 ? 0 : 1;
    int sq_side = 1 - pos_side;
    if (dbg) std::fprintf(stderr, "knight colors %d %d pos_side=%d\n", cnt0, cnt1, pos_side);
    if (std::min(cnt0, cnt1) != V - 5 || std::max(cnt0, cnt1) != V - 1) return false;

    std::unordered_set<int> occ1;
    for (auto& kv : occ) if (kv.second.size() == 1) occ1.insert(kv.first);
    int small_groups = 0;
    for (int ci = 0; ci < (int)cnf.clauses.size(); ++ci) {
        if (is_long_clause[ci]) continue;
        Clause cl = cnf.clauses[ci];
        if (cl.len < 2 || cl.len > 20) continue;
        bool ok = true;
        std::vector<int> g;
        for (int i = 0; i < cl.len; ++i) {
            int lit = cnf.lits[cl.start + i];
            if (lit <= 0 || !occ1.count(std::abs(lit))) { ok = false; break; }
            g.push_back(lit);
        }
        if (!ok) continue;
        int gi = groups.size();
        for (int lit : g) {
            int v = std::abs(lit);
            occ[v].push_back(gi);
            sign[((uint64_t)gi << 32) | (uint32_t)v] = 1;
        }
        groups.push_back(std::move(g));
        color.push_back(pos_side);
        ++small_groups;
    }
    if (dbg) std::fprintf(stderr, "knight small=%d groups=%zu occ=%zu\n", small_groups, groups.size(), occ.size());
    if (small_groups != 4 || (int)groups.size() != 2 * V - 2) return false;
    for (auto& kv : occ) if (kv.second.size() != 2) return false;

    adj.assign(groups.size(), {});
    for (auto& kv : occ) {
        int a = kv.second[0], b = kv.second[1];
        adj[a].push_back(b);
        adj[b].push_back(a);
    }
    auto flip = orient_groups(groups, adj, sign);

    std::unordered_map<int,int> pos_of, sq_of, sem;
    std::unordered_map<uint64_t,int> var_between;
    std::vector<int> primary_vars;
    primary_vars.reserve(occ.size());
    for (auto& kv : occ) {
        int var = kv.first;
        int p = -1, s = -1;
        for (int g : kv.second) {
            if (color[g] == pos_side) p = g;
            else if (color[g] == sq_side) s = g;
        }
        if (p < 0 || s < 0) return false;
        int sv = flip[p] * sign.at(((uint64_t)p << 32) | (uint32_t)var);
        pos_of[var] = p;
        sq_of[var] = s;
        sem[var] = sv;
        var_between[node_pair_key(p, s)] = var;
        primary_vars.push_back(var);
    }

    std::unordered_set<int> primary_set(primary_vars.begin(), primary_vars.end());
    std::unordered_map<uint64_t,int> pos_counts;
    std::unordered_set<uint64_t> sq_edges;
    for (auto cl : cnf.clauses) {
        if (cl.len != 3) continue;
        int plit[2], pc = 0, ac = 0;
        for (int i = 0; i < 3; ++i) {
            int lit = cnf.lits[cl.start + i];
            if (primary_set.count(std::abs(lit))) {
                if (pc < 2) plit[pc] = lit;
                ++pc;
            } else {
                ++ac;
            }
        }
        if (pc != 2 || ac != 1) continue;
        int src = 0, dst = 0;
        for (int i = 0; i < 2; ++i) {
            int lit = plit[i], var = std::abs(lit);
            bool positive_sem = ((lit > 0 ? 1 : -1) == sem[var]);
            if (positive_sem) dst = var;
            else src = var;
        }
        if (!src || !dst) return false;
        pos_counts[directed_pair_key(pos_of[src], pos_of[dst])]++;
        sq_edges.insert(directed_pair_key(sq_of[src], sq_of[dst]));
    }
    if (dbg) std::fprintf(stderr, "knight pos_counts=%zu sq_edges=%zu\n", pos_counts.size(), sq_edges.size());
    if ((int)pos_counts.size() != V - 2) return false;

    std::vector<int> pos_nodes;
    for (int g = 0; g < (int)groups.size(); ++g) if (color[g] == pos_side) pos_nodes.push_back(g);
    std::unordered_map<int,int> succ, pred;
    for (auto& kv : pos_counts) {
        int a = kv.first >> 32, b = (int)(uint32_t)kv.first;
        if (succ.count(a) || pred.count(b)) return false;
        succ[a] = b;
        pred[b] = a;
    }
    int start = -1;
    for (int p : pos_nodes) if (!pred.count(p)) {
        if (start != -1) return false;
        start = p;
    }
    if (start < 0) return false;
    std::vector<int> pos_at_index(V, -1);
    std::unordered_set<int> seen_pos;
    int cur = start;
    for (int idx = 1; idx < V; ++idx) {
        if (seen_pos.count(cur)) return false;
        seen_pos.insert(cur);
        pos_at_index[idx] = cur;
        auto it = succ.find(cur);
        if (idx == V - 1) {
            if (it != succ.end()) return false;
        } else {
            if (it == succ.end()) return false;
            cur = it->second;
        }
    }
    if ((int)seen_pos.size() != V - 1) return false;

    std::vector<int> sq_nodes;
    for (int g = 0; g < (int)groups.size(); ++g) if (color[g] == sq_side) sq_nodes.push_back(g);
    if ((int)sq_nodes.size() != V - 1) return false;
    std::unordered_map<int,int> sq_idx;
    for (int i = 0; i < (int)sq_nodes.size(); ++i) sq_idx[sq_nodes[i]] = i;
    std::vector<std::unordered_set<int>> tadj(V - 1);
    for (uint64_t key : sq_edges) {
        int a = key >> 32, b = (int)(uint32_t)key;
        auto ia = sq_idx.find(a), ib = sq_idx.find(b);
        if (ia == sq_idx.end() || ib == sq_idx.end()) continue;
        tadj[ia->second].insert(ib->second);
        tadj[ib->second].insert(ia->second);
    }
    std::vector<int> canon_to_target_idx;
    if (dbg) std::fprintf(stderr, "knight square graph edges=%zu\n", sq_edges.size());
    if (!iso_graph_missing_corner(n, tadj, canon_to_target_idx)) {
        if (dbg) std::fprintf(stderr, "knight square iso failed\n");
        return false;
    }
    std::vector<int> canon_to_group(V, -1);
    for (int ci = 0; ci < V - 1; ++ci) {
        int square = ci + 1;
        canon_to_group[square] = sq_nodes[canon_to_target_idx[ci]];
    }

    auto base_tour = tour_for_n(n);
    if ((int)base_tour.size() != V || base_tour[0] != 0) return false;
    for (int sym = 0; sym < 8; ++sym) {
        if (transform_square(0, n, sym) != 0) continue;
        for (int rv = 0; rv < 2; ++rv) {
            auto tour = tour_variant(base_tour, n, sym, rv != 0);
            std::vector<int8_t> trial(cnf.nvar + 1, 0);
            for (int var : primary_vars) trial[var] = -sem[var];
            bool ok = true;
            for (int idx = 1; idx < V; ++idx) {
                int sq = tour[idx];
                if (sq <= 0 || sq >= V || canon_to_group[sq] < 0) { ok = false; break; }
                int pg = pos_at_index[idx], sg = canon_to_group[sq];
                auto it = var_between.find(node_pair_key(pg, sg));
                if (it == var_between.end()) { ok = false; break; }
                int var = it->second;
                trial[var] = sem[var];
            }
            if (!ok) continue;
            bool complete_ok = complete_greedy(cnf, trial);
            if (dbg) std::fprintf(stderr, "knight variant sym=%d rev=%d complete=%d\n", sym, rv, complete_ok ? 1 : 0);
            if (complete_ok) {
                asg.swap(trial);
                return true;
            }
        }
    }
    return false;
}

static void print_model(const std::vector<int8_t>& asg) {
    std::cout << "s SATISFIABLE\n";
    int n = (int)asg.size() - 1;
    for (int i = 1; i <= n; ++i) {
        if (i % 1000 == 1) std::cout << "v ";
        std::cout << (asg[i] > 0 ? i : -i) << ' ';
        if (i % 1000 == 0) std::cout << "0\n";
    }
    if (n % 1000 != 0) std::cout << "0\n";
}

int main(int argc, char** argv) {
    if (argc != 3) return 1;
    CNF cnf;
    if (!read_cnf(argv[1], cnf, true)) {
        std::cout << "s UNKNOWN\n";
        return 0;
    }
    std::unordered_map<int,std::vector<int>> len_ids;
    for (int i=0;i<(int)cnf.clauses.size();++i) len_ids[cnf.clauses[i].len].push_back(i);
    std::vector<int8_t> asg;
    bool ok=false;
    int bestL=0,bestN=0;
    for(auto&kv:len_ids){ int n; if(kv.first>20 && is_square(kv.first,n)){ bestL=kv.first; bestN=n; break; } }
    int maxL = 0, knightN = 0;
    for (auto& kv : len_ids) maxL = std::max(maxL, kv.first);
    if(bestL && (int)len_ids[bestL].size()==2*bestL) {
        ok=solve_bij(cnf,bestN,len_ids[bestL],asg);
    } else if(bestL && (int)len_ids[bestL].size()==bestL) {
        ok=solve_cp(cnf,bestN,len_ids[bestL],asg);
    } else if(maxL > 20 && is_square(maxL + 1, knightN)) {
        ok=solve_knight_position(cnf,knightN,asg);
    } else {
        ok=solve_sparse(cnf,asg);
    }
    if(ok) { print_model(asg); return 10; }
    std::cout << "s UNKNOWN\n";
    return 0;
}
