#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <numeric>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>

using Clock = std::chrono::steady_clock;

static constexpr int MAX_BITS = 512;
static constexpr int WORDS = MAX_BITS / 64;

struct Mask {
    std::array<uint64_t, WORDS> w{};

    void reset() { w.fill(0); }
    bool empty() const {
        for (uint64_t x : w) if (x) return false;
        return true;
    }
    int count() const {
        int c = 0;
        for (uint64_t x : w) c += __builtin_popcountll(x);
        return c;
    }
    bool test(int i) const { return (w[i >> 6] >> (i & 63)) & 1ULL; }
    void set(int i) { w[i >> 6] |= 1ULL << (i & 63); }
    void clear(int i) { w[i >> 6] &= ~(1ULL << (i & 63)); }
    bool operator==(const Mask& o) const { return w == o.w; }
    bool operator<(const Mask& o) const {
        for (int i = WORDS - 1; i >= 0; --i) {
            if (w[i] != o.w[i]) return w[i] < o.w[i];
        }
        return false;
    }
};

static inline Mask operator|(const Mask& a, const Mask& b) {
    Mask r;
    for (int i = 0; i < WORDS; ++i) r.w[i] = a.w[i] | b.w[i];
    return r;
}
static inline Mask operator&(const Mask& a, const Mask& b) {
    Mask r;
    for (int i = 0; i < WORDS; ++i) r.w[i] = a.w[i] & b.w[i];
    return r;
}
static inline Mask operator~(const Mask& a) {
    Mask r;
    for (int i = 0; i < WORDS; ++i) r.w[i] = ~a.w[i];
    return r;
}
static inline Mask diff_mask(const Mask& a, const Mask& b) {
    Mask r;
    for (int i = 0; i < WORDS; ++i) r.w[i] = a.w[i] & ~b.w[i];
    return r;
}
static inline void or_into(Mask& a, const Mask& b) {
    for (int i = 0; i < WORDS; ++i) a.w[i] |= b.w[i];
}
static inline int inter_count(const Mask& a, const Mask& b) {
    int c = 0;
    for (int i = 0; i < WORDS; ++i) c += __builtin_popcountll(a.w[i] & b.w[i]);
    return c;
}
static inline std::vector<int> bit_indices(const Mask& m, int limit_bits) {
    std::vector<int> out;
    int max_word = (limit_bits + 63) >> 6;
    for (int wi = 0; wi < max_word; ++wi) {
        uint64_t x = m.w[wi];
        while (x) {
            uint64_t b = x & -x;
            out.push_back((wi << 6) + __builtin_ctzll(x));
            x -= b;
        }
    }
    return out;
}
static inline int first_bit(const Mask& m, int limit_bits) {
    int max_word = (limit_bits + 63) >> 6;
    for (int wi = 0; wi < max_word; ++wi) {
        if (m.w[wi]) return (wi << 6) + __builtin_ctzll(m.w[wi]);
    }
    return -1;
}
static inline std::string mask_bytes(const Mask& a, const Mask& b) {
    std::string s;
    s.resize(WORDS * 16);
    std::memcpy(s.data(), a.w.data(), WORDS * sizeof(uint64_t));
    std::memcpy(s.data() + WORDS * sizeof(uint64_t), b.w.data(), WORDS * sizeof(uint64_t));
    return s;
}
static inline Mask full_mask(int n) {
    Mask m;
    for (int i = 0; i < n; ++i) m.set(i);
    return m;
}

struct FastInput {
    FILE* f = nullptr;
    static constexpr size_t SZ = 1 << 20;
    std::array<char, SZ> buf{};
    size_t pos = 0, len = 0;

    explicit FastInput(const char* path) { f = std::fopen(path, "rb"); }
    ~FastInput() { if (f) std::fclose(f); }
    int gc() {
        if (pos >= len) {
            len = std::fread(buf.data(), 1, SZ, f);
            pos = 0;
            if (!len) return EOF;
        }
        return buf[pos++];
    }
    void skip_line() {
        int c;
        while ((c = gc()) != EOF && c != '\n') {}
    }
    bool read_word(char* out, int cap) {
        int c;
        do {
            c = gc();
            if (c == EOF) return false;
        } while (c <= ' ');
        int n = 0;
        while (c > ' ' && c != EOF) {
            if (n + 1 < cap) out[n++] = (char)c;
            c = gc();
        }
        out[n] = 0;
        return true;
    }
    bool read_positive_int(int& out) {
        int c;
        do {
            c = gc();
            if (c == EOF) return false;
        } while (c <= ' ');
        int x = 0;
        while (c > ' ' && c != EOF) {
            x = x * 10 + (c - '0');
            c = gc();
        }
        out = x;
        return true;
    }
    bool read_header(int& vars, int& clauses) {
        int c;
        while ((c = gc()) != EOF) {
            if (c == 'c') {
                skip_line();
            } else if (c == 'p') {
                char tmp[16];
                if (!read_word(tmp, 16)) return false;
                if (!read_positive_int(vars)) return false;
                if (!read_positive_int(clauses)) return false;
                return true;
            }
        }
        return false;
    }
    bool next_int(int& out) {
        int c;
        do {
            c = gc();
            if (c == EOF) return false;
            if (c == 'c') {
                skip_line();
                c = ' ';
            }
        } while (c <= ' ');
        int sign = 1;
        if (c == '-') {
            sign = -1;
            c = gc();
        }
        int x = 0;
        while (c > ' ') {
            x = x * 10 + (c - '0');
            c = gc();
        }
        out = sign * x;
        return true;
    }
};

struct CNF {
    int nvars = 0;
    int nclauses = 0;
    std::vector<int> lits;
    std::vector<uint32_t> off;

    bool parse(const char* path) {
        FastInput in(path);
        if (!in.f) return false;
        if (!in.read_header(nvars, nclauses)) return false;
        off.reserve((size_t)nclauses + 1);
        lits.reserve((size_t)nclauses * 4);
        off.push_back(0);
        int x;
        while (in.next_int(x)) {
            if (x == 0) {
                off.push_back((uint32_t)lits.size());
            } else {
                lits.push_back(x);
            }
        }
        return off.size() >= 2;
    }
    int clen(size_t c) const { return (int)(off[c + 1] - off[c]); }
    const int* cptr(size_t c) const { return lits.data() + off[c]; }
    size_t clauses() const { return off.size() - 1; }
};

static int order_var(int n, int i, int j) {
    if (i > j) std::swap(i, j);
    return i * (2 * n - i - 1) / 2 + (j - i);
}
static int a_var(int n, int order_count, int i, int j) {
    return order_count + 1 + i * n + j;
}
static int w_var(int w_start, int m, int r, int e) {
    return w_start + r * m + e;
}
static int p_var(int n, int p_start, int v, int r) {
    int c = (r < v) ? r : r - 1;
    return p_start + v * (n - 1) + c;
}
static std::pair<int,int> decode_p(int n, int p_start, int var) {
    int off = var - p_start;
    int v = off / (n - 1);
    int c = off % (n - 1);
    int r = (c < v) ? c : c + 1;
    return {v, r};
}

struct Node {
    Mask lam;
    Mask chi;
    std::vector<int> children;
};

struct DetK {
    int nh, m, W;
    std::vector<std::pair<int,int>> inc;
    std::vector<Mask> adj;
    std::vector<Mask> inc_edges;
    std::vector<Node> nodes;
    std::unordered_set<std::string> fail;
    Clock::time_point start;
    double limit_sec = 520.0;
    bool aborted = false;
    uint64_t calls = 0;
    int cover_limit = 500;
    int add_limit = 160;

    DetK(int nh_, int m_, std::vector<std::pair<int,int>> inc_, int W_, Clock::time_point st)
        : nh(nh_), m(m_), W(W_), inc(std::move(inc_)), adj(m_), inc_edges(m_), start(st) {
        for (int e = 0; e < nh; ++e) {
            auto [a, b] = inc[e];
            adj[a].set(b);
            adj[b].set(a);
            inc_edges[a].set(e);
            inc_edges[b].set(e);
        }
    }

    bool time_up() {
        double s = std::chrono::duration<double>(Clock::now() - start).count();
        if (s > limit_sec) aborted = true;
        return aborted;
    }

    Mask union_edges(const Mask& vmask) const {
        Mask out;
        for (int v : bit_indices(vmask, m)) or_into(out, inc_edges[v]);
        return out;
    }

    std::vector<Mask> components(const Mask& edges_mask, const Mask& sep_mask) const {
        Mask rem = diff_mask(edges_mask, sep_mask);
        std::vector<Mask> comps;
        while (true) {
            int s = first_bit(rem, m);
            if (s < 0) break;
            rem.clear(s);
            Mask seen;
            seen.set(s);
            std::vector<int> q{ s };
            for (size_t qi = 0; qi < q.size(); ++qi) {
                int v = q[qi];
                Mask nb = adj[v] & rem;
                for (int u : bit_indices(nb, m)) {
                    rem.clear(u);
                    seen.set(u);
                    q.push_back(u);
                }
            }
            comps.push_back(seen);
        }
        return comps;
    }

    Mask conn_between(const Mask& comp, const Mask& sep) const {
        Mask out;
        for (int e = 0; e < nh; ++e) {
            auto [a, b] = inc[e];
            bool ca = comp.test(a), cb = comp.test(b);
            if (ca == cb) continue;
            if (sep.test(a) || sep.test(b)) out.set(e);
        }
        return out;
    }

    int matching_lb(const Mask& uncovered) const {
        Mask used;
        int lb = 0;
        for (int e : bit_indices(uncovered, nh)) {
            auto [a, b] = inc[e];
            if (used.test(a) || used.test(b)) continue;
            used.set(a);
            used.set(b);
            ++lb;
        }
        return lb;
    }

    std::vector<Mask> cover_candidates(const Mask& conn_edges, const Mask& current_edges) {
        if (conn_edges.empty()) return {Mask{}};
        Mask cand_vertices;
        for (int e : bit_indices(conn_edges, nh)) {
            cand_vertices.set(inc[e].first);
            cand_vertices.set(inc[e].second);
        }
        std::vector<Mask> cover_by(m);
        for (int v : bit_indices(cand_vertices, m)) cover_by[v] = inc_edges[v] & conn_edges;
        std::vector<Mask> results;
        std::function<void(Mask, Mask, Mask)> rec = [&](Mask uncovered, Mask chosen, Mask cand) {
            if ((int)results.size() >= cover_limit) return;
            if (uncovered.empty()) {
                results.push_back(chosen);
                return;
            }
            if (chosen.count() >= W) return;
            if (chosen.count() + matching_lb(uncovered) > W) return;
            int best_e = -1;
            int best_opts = 3;
            for (int e : bit_indices(uncovered, nh)) {
                int opts = (cand.test(inc[e].first) ? 1 : 0) + (cand.test(inc[e].second) ? 1 : 0);
                if (opts < best_opts) {
                    best_opts = opts;
                    best_e = e;
                    if (opts <= 1) break;
                }
            }
            if (best_e < 0 || best_opts == 0) return;
            std::array<int,2> opts = {inc[best_e].first, inc[best_e].second};
            std::vector<int> ov;
            for (int v : opts) if (cand.test(v)) ov.push_back(v);
            std::sort(ov.begin(), ov.end(), [&](int a, int b) {
                int ca = inter_count(cover_by[a], uncovered);
                int cb = inter_count(cover_by[b], uncovered);
                if (ca != cb) return ca > cb;
                bool ia = current_edges.test(a), ib = current_edges.test(b);
                if (ia != ib) return ia > ib;
                return a < b;
            });
            for (int v : ov) {
                Mask next_un = diff_mask(uncovered, cover_by[v]);
                Mask next_ch = chosen;
                next_ch.set(v);
                Mask next_cand = cand;
                next_cand.clear(v);
                rec(next_un, next_ch, next_cand);
            }
        };
        rec(conn_edges, Mask{}, cand_vertices);
        std::sort(results.begin(), results.end(), [&](const Mask& a, const Mask& b) {
            int ca = a.count(), cb = b.count();
            if (ca != cb) return ca < cb;
            int ia = inter_count(a, current_edges), ib = inter_count(b, current_edges);
            if (ia != ib) return ia > ib;
            return a < b;
        });
        results.erase(std::unique(results.begin(), results.end()), results.end());
        if ((int)results.size() > cover_limit) results.resize(cover_limit);
        return results;
    }

    int decomp(const Mask& edges_mask, const Mask& conn_edges) {
        ++calls;
        if ((calls & 2047ULL) == 0 && time_up()) return -1;
        std::string key = mask_bytes(edges_mask, conn_edges);
        if (fail.find(key) != fail.end()) return -1;
        if (edges_mask.count() <= W) {
            Node nd;
            nd.lam = edges_mask;
            nd.chi = union_edges(edges_mask);
            int id = (int)nodes.size();
            nodes.push_back(std::move(nd));
            return id;
        }
        auto covs = cover_candidates(conn_edges, edges_mask);
        for (const Mask& cov : covs) {
            Mask in_cov = cov & edges_mask;
            std::vector<Mask> adds;
            if (!in_cov.empty()) {
                adds.push_back(Mask{});
            } else {
                if (cov.count() >= W) continue;
                struct Opt { int maxc, negcomps, negdeg, v; };
                std::vector<Opt> opts;
                for (int a : bit_indices(edges_mask, m)) {
                    Mask sep = cov;
                    sep.set(a);
                    auto comps = components(edges_mask, sep);
                    int maxc = 0;
                    for (const auto& c : comps) maxc = std::max(maxc, c.count());
                    opts.push_back({maxc, -(int)comps.size(), -inter_count(adj[a], edges_mask), a});
                }
                std::sort(opts.begin(), opts.end(), [](const Opt& x, const Opt& y) {
                    if (x.maxc != y.maxc) return x.maxc < y.maxc;
                    if (x.negcomps != y.negcomps) return x.negcomps < y.negcomps;
                    if (x.negdeg != y.negdeg) return x.negdeg < y.negdeg;
                    return x.v < y.v;
                });
                int lim = std::min(add_limit, (int)opts.size());
                for (int i = 0; i < lim; ++i) {
                    Mask a;
                    a.set(opts[i].v);
                    adds.push_back(a);
                }
            }
            for (const Mask& add : adds) {
                if (time_up()) return -1;
                Mask sep = cov | add;
                Mask in_sep = sep & edges_mask;
                if (in_sep.empty()) continue;
                auto comps = components(edges_mask, sep);
                if (comps.size() == 1 && comps[0] == edges_mask) continue;
                std::sort(comps.begin(), comps.end(), [](const Mask& a, const Mask& b) {
                    return a.count() > b.count();
                });
                size_t snap = nodes.size();
                std::vector<int> child_ids;
                bool ok = true;
                for (const Mask& comp : comps) {
                    Mask child_conn = conn_between(comp, sep);
                    int cid = decomp(comp, child_conn);
                    if (cid < 0) {
                        ok = false;
                        break;
                    }
                    child_ids.push_back(cid);
                }
                if (ok) {
                    Node nd;
                    nd.lam = sep;
                    nd.chi = conn_edges | union_edges(in_sep);
                    nd.children = std::move(child_ids);
                    int id = (int)nodes.size();
                    nodes.push_back(std::move(nd));
                    return id;
                }
                nodes.resize(snap);
            }
        }
        fail.insert(std::move(key));
        return -1;
    }
};

struct Solver {
    CNF cnf;
    int n = 0, m = 0, W = 0;
    int order_count = 0, a_start = 0, w_start = 0, p_start = 0, aux_start = 0;
    int per_aux = 0;
    std::vector<Mask> hyperedge_mask;
    std::vector<std::vector<int>> hyperedge_vertices;
    std::vector<std::pair<int,int>> dual_inc;
    std::vector<unsigned char> val;
    Clock::time_point start;
    const char* debug = std::getenv("LYMPHODEBUG");

    bool detect_layout() {
        int triples = 0;
        for (size_t idx = 0; idx + 2 < cnf.clauses(); idx += 3) {
            if (cnf.clen(idx) != 2 || cnf.clen(idx + 1) != 2 || cnf.clen(idx + 2) != 2) break;
            const int* c1 = cnf.cptr(idx);
            const int* c2 = cnf.cptr(idx + 1);
            const int* c3 = cnf.cptr(idx + 2);
            if (c1[0] < 0 && c1[1] < 0 && c2[0] < 0 && c2[1] < 0 && c3[0] > 0 && c3[1] < 0
                && -c2[0] == c3[0] && c1[0] == c2[1] && c1[1] == c3[1]) {
                ++triples;
            } else {
                break;
            }
        }
        long long disc = 1LL + 8LL * triples;
        int root = (int)(std::sqrt((double)disc) + 0.5);
        n = (1 + root) / 2;
        if (n <= 1 || n * (n - 1) / 2 != triples || n > MAX_BITS) return false;
        order_count = triples;
        a_start = order_count + 1;
        int a_end = a_start + n * n - 1;
        w_start = a_end + 1;
        int best_diff = 1 << 30;
        int best_p = 0;
        for (size_t ci = 0; ci < cnf.clauses(); ++ci) {
            if (cnf.clen(ci) != 4) continue;
            const int* c = cnf.cptr(ci);
            if (c[0] < 0 && -c[0] >= a_start && -c[0] <= a_end && c[1] < 0 && c[2] < 0
                && -c[2] == w_start && c[3] > w_start) {
                int diff = c[3] - w_start;
                if (diff > 0 && diff < best_diff) {
                    best_diff = diff;
                    best_p = -c[1];
                }
            }
        }
        if (best_diff == (1 << 30)) return false;
        m = best_diff;
        if (m <= 0 || m > MAX_BITS) return false;
        p_start = w_start + n * m;
        if (best_p != p_start) return false;
        aux_start = p_start + n * (n - 1);
        long long semantic = (long long)aux_start - 1;
        long long aux_total = (long long)cnf.nvars - semantic;
        if (aux_total < 0 || aux_total % n != 0) return false;
        per_aux = (int)(aux_total / n);
        W = 0;
        for (int k = 1; k <= m; ++k) {
            int per = k * m - k * (k + 1) / 2;
            if (per == per_aux) {
                W = k;
                break;
            }
        }
        return W > 0;
    }

    bool extract_hypergraph() {
        hyperedge_mask.assign(m, Mask{});
        int w_end = w_start + n * m - 1;
        int p_end = p_start + n * (n - 1) - 1;
        for (size_t ci = 0; ci < cnf.clauses(); ++ci) {
            if (cnf.clen(ci) != 2) continue;
            const int* c = cnf.cptr(ci);
            for (int sw = 0; sw < 2; ++sw) {
                int a = c[sw], b = c[1 - sw];
                if (a > 0 && a >= p_start && a <= p_end && b < 0 && -b >= w_start && -b <= w_end) {
                    auto [v, row] = decode_p(n, p_start, a);
                    int off = -b - w_start;
                    int wrow = off / m;
                    int e = off % m;
                    if (wrow == row && v >= 0 && v < n && e >= 0 && e < m) hyperedge_mask[e].set(v);
                }
            }
        }
        hyperedge_vertices.assign(m, {});
        std::vector<int> deg(n, 0);
        for (int e = 0; e < m; ++e) {
            for (int v : bit_indices(hyperedge_mask[e], n)) {
                hyperedge_vertices[e].push_back(v);
                deg[v]++;
            }
            if (hyperedge_vertices[e].empty()) return false;
        }
        dual_inc.assign(n, {-1, -1});
        for (int v = 0; v < n; ++v) {
            if (deg[v] != 2) return false;
            int k = 0;
            for (int e = 0; e < m; ++e) if (hyperedge_mask[e].test(v)) {
                if (k == 0) dual_inc[v].first = e;
                else dual_inc[v].second = e;
                ++k;
            }
        }
        return true;
    }

    std::vector<Mask> compute_arcs(const std::vector<int>& order) const {
        std::vector<Mask> primal(n);
        for (int e = 0; e < m; ++e) {
            const auto& vs = hyperedge_vertices[e];
            for (size_t i = 0; i < vs.size(); ++i) {
                for (size_t j = i + 1; j < vs.size(); ++j) {
                    primal[vs[i]].set(vs[j]);
                    primal[vs[j]].set(vs[i]);
                }
            }
        }
        Mask rem = full_mask(n);
        std::vector<Mask> arcs(n);
        for (int v : order) {
            Mask nbrs = primal[v] & rem;
            nbrs.clear(v);
            arcs[v] = arcs[v] | nbrs;
            for (int u : bit_indices(nbrs, n)) {
                Mask add = nbrs;
                add.clear(u);
                or_into(primal[u], add);
            }
            rem.clear(v);
        }
        return arcs;
    }

    std::vector<Mask> p_closure(const std::vector<Mask>& covers, const std::vector<Mask>& arcs, const std::vector<int>& pos) const {
        std::vector<Mask> p(n);
        for (int row = 0; row < n; ++row) {
            for (int v = 0; v < n; ++v) {
                if (row != v && pos[row] < pos[v]) p[v].set(row);
            }
        }
        for (int row = 0; row < n; ++row) {
            for (int e : bit_indices(covers[row], m)) {
                for (int v : hyperedge_vertices[e]) if (v != row) p[v].set(row);
            }
        }
        bool changed = true;
        while (changed) {
            changed = false;
            for (int j = 0; j < n; ++j) {
                for (int k : bit_indices(arcs[j], n)) {
                    for (int i = 0; i < n; ++i) {
                        if (i != j && i != k && p[i].test(k) && !p[i].test(j)) {
                            p[i].set(j);
                            changed = true;
                        }
                    }
                }
            }
        }
        return p;
    }

    bool build_model_from_decomp(int root, DetK& det) {
        std::vector<int> parent(det.nodes.size(), -2);
        std::vector<int> depth(det.nodes.size(), -1);
        std::vector<int> stack{root};
        parent[root] = -1;
        depth[root] = 0;
        for (size_t qi = 0; qi < stack.size(); ++qi) {
            int x = stack[qi];
            for (int c : det.nodes[x].children) {
                parent[c] = x;
                depth[c] = depth[x] + 1;
                stack.push_back(c);
            }
        }
        std::vector<int> f(n, -1);
        for (int v = 0; v < n; ++v) {
            int best = -1;
            for (int i = 0; i < (int)det.nodes.size(); ++i) {
                if (depth[i] >= 0 && det.nodes[i].chi.test(v)) {
                    if (best < 0 || depth[i] < depth[best]) best = i;
                }
            }
            if (best < 0) return false;
            f[v] = best;
        }
        std::vector<int> order(n);
        std::iota(order.begin(), order.end(), 0);
        std::sort(order.begin(), order.end(), [&](int a, int b) {
            if (depth[f[a]] != depth[f[b]]) return depth[f[a]] > depth[f[b]];
            if (f[a] != f[b]) return f[a] < f[b];
            return a < b;
        });
        std::vector<int> pos(n);
        for (int i = 0; i < n; ++i) pos[order[i]] = i;
        std::vector<Mask> covers(n);
        for (int v = 0; v < n; ++v) {
            covers[v] = det.nodes[f[v]].lam;
            if (covers[v].count() > W) return false;
        }
        auto arcs = compute_arcs(order);
        std::vector<Mask> p;
        for (int iter = 0; iter < n; ++iter) {
            p = p_closure(covers, arcs, pos);
            int added = 0;
            for (int i = 0; i < n; ++i) {
                for (int j : bit_indices(arcs[i], n)) {
                    for (int k : bit_indices(arcs[j], n)) {
                        if (i != k && p[i].test(k) && !arcs[i].test(k) && pos[i] < pos[k]) {
                            arcs[i].set(k);
                            ++added;
                        }
                    }
                }
            }
            if (!added) break;
        }
        p = p_closure(covers, arcs, pos);

        val.assign((size_t)cnf.nvars + 1, 0);
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (pos[i] < pos[j]) val[order_var(n, i, j)] = 1;
            }
        }
        for (int i = 0; i < n; ++i) {
            for (int j : bit_indices(arcs[i], n)) val[a_var(n, order_count, i, j)] = 1;
        }
        for (int r = 0; r < n; ++r) {
            for (int e : bit_indices(covers[r], m)) val[w_var(w_start, m, r, e)] = 1;
        }
        for (int v = 0; v < n; ++v) {
            for (int r : bit_indices(p[v], n)) {
                if (v != r) val[p_var(n, p_start, v, r)] = 1;
            }
        }
        for (int r = 0; r < n; ++r) {
            int cnt = 0;
            int base = aux_start + r * per_aux;
            int prefix_base = 0;
            for (int t = 1; t <= m - 1; ++t) {
                if (val[w_var(w_start, m, r, t - 1)]) ++cnt;
                int lim = std::min(t, W);
                for (int k = 1; k <= lim; ++k) {
                    int var = base + prefix_base + (k - 1);
                    if (cnt >= k && var <= cnf.nvars) val[var] = 1;
                }
                prefix_base += lim;
            }
        }
        return true;
    }

    bool verify_model() const {
        if ((int)val.size() != cnf.nvars + 1) return false;
        for (size_t ci = 0; ci < cnf.clauses(); ++ci) {
            bool ok = false;
            const int* c = cnf.cptr(ci);
            int len = cnf.clen(ci);
            for (int i = 0; i < len; ++i) {
                int lit = c[i];
                bool b = val[std::abs(lit)] != 0;
                if ((lit > 0 && b) || (lit < 0 && !b)) {
                    ok = true;
                    break;
                }
            }
            if (!ok) return false;
        }
        return true;
    }

    bool solve(const char* path) {
        start = Clock::now();
        if (!cnf.parse(path)) { if (debug) std::fprintf(stderr, "parse failed\n"); return false; }
        if (!detect_layout()) { if (debug) std::fprintf(stderr, "layout failed\n"); return false; }
        if (!extract_hypergraph()) { if (debug) std::fprintf(stderr, "extract failed n=%d m=%d W=%d\n", n, m, W); return false; }
        DetK det(n, m, dual_inc, W, start);
        if (W >= 6) {
            det.cover_limit = 800;
            det.add_limit = 240;
        }
        int root = det.decomp(full_mask(m), Mask{});
        if (root < 0 || det.aborted) { if (debug) std::fprintf(stderr, "decomp failed calls=%llu fail=%zu aborted=%d\n", (unsigned long long)det.calls, det.fail.size(), det.aborted); return false; }
        if (debug) std::fprintf(stderr, "decomp ok calls=%llu fail=%zu nodes=%zu\n", (unsigned long long)det.calls, det.fail.size(), det.nodes.size());
        if (!build_model_from_decomp(root, det)) { if (debug) std::fprintf(stderr, "build model failed\n"); return false; }
        bool ok = verify_model();
        if (debug && !ok) std::fprintf(stderr, "verify failed\n");
        return ok;
    }
};

static void print_unknown() {
    std::printf("s UNKNOWN\n");
}

static void print_sat(const std::vector<unsigned char>& val, int nvars) {
    std::printf("s SATISFIABLE\n");
    int on_line = 0;
    std::printf("v");
    for (int i = 1; i <= nvars; ++i) {
        int lit = val[i] ? i : -i;
        std::printf(" %d", lit);
        if (++on_line >= 1000) {
            std::printf(" 0\nv");
            on_line = 0;
        }
    }
    std::printf(" 0\n");
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Solver s;
    if (s.solve(argv[1])) {
        print_sat(s.val, s.cnf.nvars);
        return 10;
    }
    print_unknown();
    return 0;
}
