#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <functional>
#include <iostream>
#include <mutex>
#include <numeric>
#include <set>
#include <string>
#include <thread>
#include <unordered_set>
#include <vector>

using Clock = std::chrono::steady_clock;

struct Clause {
    std::vector<int> lits;
    int w0 = 0;
    int w1 = 0;
};

struct Solver {
    int nvars = 0;
    int nclauses_decl = 0;
    int front = 0;
    std::vector<Clause> clauses;
    std::vector<std::vector<int>> watches;
    std::vector<int> branch_order;
    std::vector<signed char> val;
    std::vector<int> level;
    std::vector<int> reason;
    std::vector<int> reason_lit;
    std::vector<int> trail;
    std::vector<int> q;
    std::vector<size_t> trail_lim;
    std::vector<size_t> q_lim;
    std::vector<size_t> qhead_lim;
    size_t qhead = 0;
    int decision_level = 0;
    long long nodes = 0;
    long long conflicts = 0;
    int conflict_clause = -1;
    Clock::time_point deadline;
    bool timed_out = false;
    bool prefer_true = false;

    struct Run {
        int start = 0;
        int end = 0;
        int col = 0;
    };

    struct GateGroup {
        std::vector<int> sum_vars;
        int parity = 0;
        std::vector<int> carry_vars;
        int cout = 0;
    };

    struct StaticPropagator {
        const std::vector<Clause>* clauses = nullptr;
        int nvars = 0;
        std::vector<std::vector<int>> bin;
        std::vector<std::vector<int>> occ;
        std::vector<int> stamp;
        std::vector<signed char> val;
        std::vector<int> queue;
        std::vector<int> trail;
        int tick = 1;

        int lit_index(int lit) const {
            int v = std::abs(lit) - 1;
            return (v << 1) ^ (lit < 0);
        }

        void build(const std::vector<Clause>& all, int nv, const std::vector<int>& ids) {
            clauses = &all;
            nvars = nv;
            bin.assign(2 * nvars, {});
            occ.assign(2 * nvars, {});
            stamp.assign(nvars + 1, 0);
            val.assign(nvars + 1, 0);
            for (int ci : ids) {
                const auto& lits = all[ci].lits;
                if (lits.size() == 2) {
                    bin[lit_index(lits[0])].push_back(lits[1]);
                    bin[lit_index(lits[1])].push_back(lits[0]);
                } else {
                    for (int lit : lits) {
                        occ[lit_index(lit)].push_back(ci);
                    }
                }
            }
        }

        signed char lit_value(int lit) const {
            int v = std::abs(lit);
            if (stamp[v] != tick) return 0;
            bool sat = (val[v] > 0) == (lit > 0);
            return sat ? 1 : -1;
        }

        bool enqueue(int lit) {
            int v = std::abs(lit);
            signed char want = lit > 0 ? 1 : -1;
            if (stamp[v] == tick) return val[v] == want;
            stamp[v] = tick;
            val[v] = want;
            queue.push_back(lit);
            return true;
        }

        bool eval(const std::vector<int>& assumptions, const std::vector<int>& query, std::string& key) {
            ++tick;
            if (tick == 0x3fffffff) {
                std::fill(stamp.begin(), stamp.end(), 0);
                tick = 1;
            }
            queue.clear();
            size_t qhead = 0;
            for (int lit : assumptions) {
                if (!enqueue(lit)) return false;
            }
            while (qhead < queue.size()) {
                int false_lit = -queue[qhead++];
                int idx = lit_index(false_lit);
                for (int implied : bin[idx]) {
                    if (!enqueue(implied)) return false;
                }
                for (int ci : occ[idx]) {
                    const Clause& c = (*clauses)[ci];
                    bool sat = false;
                    int unassigned = 0;
                    int last = 0;
                    for (int lit : c.lits) {
                        signed char lv = lit_value(lit);
                        if (lv == 1) {
                            sat = true;
                            break;
                        }
                        if (lv == 0) {
                            ++unassigned;
                            last = lit;
                        }
                    }
                    if (sat) continue;
                    if (unassigned == 0) return false;
                    if (unassigned == 1 && !enqueue(last)) return false;
                }
            }
            key.assign((query.size() + 7) / 8, '\0');
            for (size_t i = 0; i < query.size(); ++i) {
                int v = query[i];
                if (stamp[v] != tick) return false;
                if (val[v] > 0) key[i >> 3] = static_cast<char>(key[i >> 3] | (1u << (i & 7)));
            }
            return true;
        }

        void reset_state() {
            std::fill(val.begin(), val.end(), 0);
            queue.clear();
            trail.clear();
        }

        bool assign_state(int lit) {
            int v = std::abs(lit);
            signed char want = lit > 0 ? 1 : -1;
            if (val[v] != 0) return val[v] == want;
            val[v] = want;
            trail.push_back(v);
            queue.push_back(lit);
            return true;
        }

        bool propagate_state(size_t& qhead) {
            while (qhead < queue.size()) {
                int false_lit = -queue[qhead++];
                int idx = lit_index(false_lit);
                for (int implied : bin[idx]) {
                    if (!assign_state(implied)) return false;
                }
                for (int ci : occ[idx]) {
                    const Clause& c = (*clauses)[ci];
                    bool sat = false;
                    int unassigned = 0;
                    int last = 0;
                    for (int lit : c.lits) {
                        int v = std::abs(lit);
                        signed char vv = val[v];
                        signed char lv = 0;
                        if (vv != 0) lv = ((vv > 0) == (lit > 0)) ? 1 : -1;
                        if (lv == 1) {
                            sat = true;
                            break;
                        }
                        if (lv == 0) {
                            ++unassigned;
                            last = lit;
                        }
                    }
                    if (sat) continue;
                    if (unassigned == 0) return false;
                    if (unassigned == 1 && !assign_state(last)) return false;
                }
            }
            return true;
        }

        void backtrack_state(size_t trail_mark, size_t queue_mark, size_t& qhead, size_t qhead_mark) {
            for (size_t i = trail.size(); i > trail_mark; --i) {
                val[trail[i - 1]] = 0;
            }
            trail.resize(trail_mark);
            queue.resize(queue_mark);
            qhead = qhead_mark;
        }

        bool key_state(const std::vector<int>& query, std::string& key) const {
            key.assign((query.size() + 7) / 8, '\0');
            for (size_t i = 0; i < query.size(); ++i) {
                int v = query[i];
                if (val[v] == 0) return false;
                if (val[v] > 0) key[i >> 3] = static_cast<char>(key[i >> 3] | (1u << (i & 7)));
            }
            return true;
        }
    };

    int lit_index(int lit) const {
        int v = std::abs(lit) - 1;
        return (v << 1) ^ (lit < 0);
    }

    signed char lit_value(int lit) const {
        signed char x = val[std::abs(lit)];
        if (x == 0) return 0;
        bool sat = (x > 0) == (lit > 0);
        return sat ? 1 : -1;
    }

    bool enqueue(int lit, int why = -1) {
        int v = std::abs(lit);
        signed char want = lit > 0 ? 1 : -1;
        if (val[v] != 0) return val[v] == want;
        val[v] = want;
        level[v] = decision_level;
        reason[v] = why;
        reason_lit[v] = lit;
        trail.push_back(lit);
        q.push_back(lit);
        return true;
    }

    bool parse(const char* path) {
        std::ifstream in(path);
        if (!in) return false;
        std::string tok;
        while (in >> tok) {
            if (tok == "c") {
                std::string rest;
                std::getline(in, rest);
            } else if (tok == "p") {
                std::string fmt;
                in >> fmt >> nvars >> nclauses_decl;
                clauses.reserve(nclauses_decl);
                break;
            }
        }
        if (nvars <= 0) return false;
        std::vector<int> cur;
        int lit;
        while (in >> lit) {
            if (lit == 0) {
                if (!cur.empty()) {
                    if (front == 0 && cur.size() > 4) {
                        bool leading = true;
                        for (size_t i = 0; i < cur.size(); ++i) {
                            if (cur[i] != -static_cast<int>(i + 1)) {
                                leading = false;
                                break;
                            }
                        }
                        if (leading) front = static_cast<int>(cur.size());
                    }
                    Clause c;
                    c.lits.swap(cur);
                    clauses.push_back(std::move(c));
                } else {
                    Clause c;
                    clauses.push_back(std::move(c));
                }
            } else {
                if (std::abs(lit) > nvars) return false;
                cur.push_back(lit);
            }
        }
        return front >= 1 && front <= 256 && !clauses.empty();
    }

    std::vector<Run> parse_selector_runs(int base_end, const std::vector<int>& selector_col) const {
        std::vector<Run> runs;
        int i = base_end;
        while (i + 1 < static_cast<int>(clauses.size())) {
            if (clauses[i].lits.size() == 2 && clauses[i + 1].lits.size() == 2) {
                int a = clauses[i].lits[0], b = clauses[i].lits[1];
                int c = clauses[i + 1].lits[0], d = clauses[i + 1].lits[1];
                int s = -a;
                if (s > 0 && s < static_cast<int>(selector_col.size()) && selector_col[s] >= 0 &&
                    c == s && d == -b && b > front) {
                    int start = i;
                    int col = selector_col[s];
                    i += 2;
                    while (i + 1 < static_cast<int>(clauses.size()) &&
                           clauses[i].lits.size() == 2 && clauses[i + 1].lits.size() == 2) {
                        int a2 = clauses[i].lits[0], b2 = clauses[i].lits[1];
                        int c2 = clauses[i + 1].lits[0], d2 = clauses[i + 1].lits[1];
                        if (a2 == -s && c2 == s && d2 == -b2 && b2 > front) i += 2;
                        else break;
                    }
                    runs.push_back({start, i, col});
                    continue;
                }
            }
            ++i;
        }
        return runs;
    }

    static bool contains_sorted(const std::vector<int>& xs, int v) {
        return std::binary_search(xs.begin(), xs.end(), v);
    }

    std::vector<int> vars_in_range(int start, int end) const {
        std::vector<int> out;
        std::unordered_set<int> seen;
        seen.reserve(static_cast<size_t>(std::max(16, end - start)));
        for (int ci = start; ci < end; ++ci) {
            for (int lit : clauses[ci].lits) {
                int v = std::abs(lit);
                if (seen.insert(v).second) out.push_back(v);
            }
        }
        std::sort(out.begin(), out.end());
        return out;
    }

    int first_clause_with_any(int start, int end, const std::vector<int>& a, const std::vector<int>& b) const {
        for (int ci = start; ci < end; ++ci) {
            for (int lit : clauses[ci].lits) {
                int v = std::abs(lit);
                if (contains_sorted(a, v) || contains_sorted(b, v)) return ci;
            }
        }
        return -1;
    }

    bool sat_masks_for_chunk(int start, int len, std::vector<int>& vs, std::vector<int>& sat) const {
        std::set<int> s;
        for (int ci = start; ci < start + len; ++ci) {
            for (int lit : clauses[ci].lits) s.insert(std::abs(lit));
        }
        if (s.empty() || s.size() > 4) return false;
        vs.assign(s.begin(), s.end());
        sat.clear();
        int total = 1 << static_cast<int>(vs.size());
        for (int mask = 0; mask < total; ++mask) {
            bool ok = true;
            for (int ci = start; ci < start + len && ok; ++ci) {
                bool csat = false;
                for (int lit : clauses[ci].lits) {
                    int idx = static_cast<int>(std::lower_bound(vs.begin(), vs.end(), std::abs(lit)) - vs.begin());
                    bool bit = ((mask >> idx) & 1) != 0;
                    if (bit == (lit > 0)) {
                        csat = true;
                        break;
                    }
                }
                ok = csat;
            }
            if (ok) sat.push_back(mask);
        }
        return true;
    }

    bool parse_parity(int start, int len, std::vector<int>& vs, int& parity) const {
        std::vector<int> sat;
        if (!sat_masks_for_chunk(start, len, vs, sat)) return false;
        int total = 1 << static_cast<int>(vs.size());
        for (int p = 0; p <= 1; ++p) {
            std::vector<int> want;
            for (int mask = 0; mask < total; ++mask) {
                if ((__builtin_popcount(static_cast<unsigned int>(mask)) & 1) == p) want.push_back(mask);
            }
            if (sat == want) {
                parity = p;
                return true;
            }
        }
        return false;
    }

    bool parse_carry(int start, int len, std::vector<int>& vs, int& out) const {
        std::vector<int> sat;
        if (!sat_masks_for_chunk(start, len, vs, sat)) return false;
        auto bit_at = [&](int mask, int var) {
            int idx = static_cast<int>(std::lower_bound(vs.begin(), vs.end(), var) - vs.begin());
            return (mask >> idx) & 1;
        };
        int total = 1 << static_cast<int>(vs.size());
        for (int ov : vs) {
            std::vector<int> ins;
            for (int v : vs) if (v != ov) ins.push_back(v);
            std::vector<int> want;
            for (int mask = 0; mask < total; ++mask) {
                if (bit_at(mask, ov) == 0) want.push_back(mask);
            }
            if (sat == want) {
                out = ov;
                return true;
            }
            if (ins.size() == 2) {
                want.clear();
                for (int mask = 0; mask < total; ++mask) {
                    if (bit_at(mask, ov) == (bit_at(mask, ins[0]) & bit_at(mask, ins[1]))) want.push_back(mask);
                }
                if (sat == want) {
                    out = ov;
                    return true;
                }
            }
            if (ins.size() == 3) {
                want.clear();
                for (int mask = 0; mask < total; ++mask) {
                    int sum = bit_at(mask, ins[0]) + bit_at(mask, ins[1]) + bit_at(mask, ins[2]);
                    if (bit_at(mask, ov) == (sum >= 2)) want.push_back(mask);
                }
                if (sat == want) {
                    out = ov;
                    return true;
                }
            }
        }
        if (vs.size() == 2) {
            std::vector<int> want;
            for (int mask = 0; mask < 4; ++mask) {
                if (!(bit_at(mask, vs[0]) & bit_at(mask, vs[1]))) want.push_back(mask);
            }
            if (sat == want) {
                out = 0;
                return true;
            }
        }
        if (vs.size() == 3) {
            std::vector<int> want;
            for (int mask = 0; mask < 8; ++mask) {
                if (bit_at(mask, vs[0]) + bit_at(mask, vs[1]) + bit_at(mask, vs[2]) < 2) want.push_back(mask);
            }
            if (sat == want) {
                out = 0;
                return true;
            }
        }
        return false;
    }

    bool scan_adder(int start, int end, std::vector<GateGroup>& groups) const {
        groups.clear();
        int p = start;
        while (p < end) {
            std::vector<int> sv;
            int parity = 0;
            int plen = 0;
            for (int len : {8, 4, 2}) {
                if (p + len <= end && parse_parity(p, len, sv, parity)) {
                    plen = len;
                    break;
                }
            }
            if (plen == 0) return false;
            p += plen;
            std::vector<int> cv;
            int cout = 0;
            int clen = 0;
            for (int len : {6, 4, 3, 2, 1}) {
                if (p + len <= end && parse_carry(p, len, cv, cout)) {
                    clen = len;
                    break;
                }
            }
            p += clen;
            groups.push_back({sv, parity, cv, cout});
        }
        return true;
    }

    bool propagate_slice_value(int start, int end, int assumption,
                               const std::vector<std::pair<int, int>>& queries,
                               std::vector<int>& true_positions) const {
        std::vector<int> stamp(nvars + 1, 0);
        std::vector<signed char> pval(nvars + 1, 0);
        int tick = 1;
        auto lit_val = [&](int lit) -> signed char {
            int v = std::abs(lit);
            if (stamp[v] != tick) return 0;
            return ((pval[v] > 0) == (lit > 0)) ? 1 : -1;
        };
        auto assign = [&](int lit) -> bool {
            int v = std::abs(lit);
            signed char want = lit > 0 ? 1 : -1;
            if (stamp[v] == tick) return pval[v] == want;
            stamp[v] = tick;
            pval[v] = want;
            return true;
        };
        if (!assign(assumption)) return false;
        bool changed = true;
        int passes = 0;
        while (changed) {
            changed = false;
            if (++passes > 256) return false;
            for (int ci = start; ci < end; ++ci) {
                bool sat = false;
                int unassigned = 0;
                int last = 0;
                for (int lit : clauses[ci].lits) {
                    signed char lv = lit_val(lit);
                    if (lv == 1) {
                        sat = true;
                        break;
                    }
                    if (lv == 0) {
                        ++unassigned;
                        last = lit;
                    }
                }
                if (sat) continue;
                if (unassigned == 0) return false;
                if (unassigned == 1) {
                    if (!assign(last)) return false;
                    changed = true;
                }
            }
        }
        true_positions.clear();
        for (auto [pos, var] : queries) {
            if (stamp[var] == tick && pval[var] > 0) true_positions.push_back(pos);
        }
        return true;
    }

    bool recover_relaxed_system(std::vector<std::vector<long long>>& C, std::vector<long long>& d) const {
        if (front <= 1 || front > 48) return false;
        const int base_end = 1 + 4 * front;
        if (static_cast<int>(clauses.size()) <= base_end) return false;
        std::vector<int> selector_col(nvars + 1, -1);
        std::vector<unsigned char> is_selector(nvars + 1, 0);
        for (int j = 0; j < front; ++j) {
            int s = front + 2 * (j + 1);
            if (s > nvars) return false;
            selector_col[s] = j;
            is_selector[s] = 1;
        }
        std::vector<int> first(nvars + 1, static_cast<int>(clauses.size()) + 1);
        for (int ci = 0; ci < static_cast<int>(clauses.size()); ++ci) {
            for (int lit : clauses[ci].lits) {
                int v = std::abs(lit);
                if (first[v] > ci) first[v] = ci;
            }
        }
        std::vector<Run> runs = parse_selector_runs(base_end, selector_col);
        if (runs.empty()) return false;
        std::vector<std::vector<int>> grid;
        std::vector<int> cur(front, -1);
        int last_col = -1;
        for (int ri = 0; ri < static_cast<int>(runs.size()); ++ri) {
            if (runs[ri].col <= last_col) {
                grid.push_back(cur);
                std::fill(cur.begin(), cur.end(), -1);
            }
            cur[runs[ri].col] = ri;
            last_col = runs[ri].col;
        }
        grid.push_back(cur);
        int rows = static_cast<int>(grid.size());
        if (rows <= 0 || rows > 80) return false;
        C.assign(rows, std::vector<long long>(front, 0));
        d.assign(rows, 0);

        for (int r = 0; r < rows; ++r) {
            int next_first_start = static_cast<int>(clauses.size());
            if (r + 1 < rows) {
                for (int j = 0; j < front; ++j) {
                    if (grid[r + 1][j] >= 0) {
                        next_first_start = runs[grid[r + 1][j]].start;
                        break;
                    }
                }
            }
            int row_end = next_first_start;
            std::vector<int> acc_map(256, 0);
            std::vector<int> first_term_map(256, 0);
            bool have_first_term_map = false;
            std::vector<int> target_bits(256, -1);

            for (int k = 1; k < front; ++k) {
                if (grid[r][k] < 0) {
                    C[r][k] = 0;
                    continue;
                }
                const Run& run = runs[grid[r][k]];
                int block_end = row_end;
                for (int t = k + 1; t < front; ++t) {
                    if (grid[r][t] >= 0) {
                        block_end = runs[grid[r][t]].start;
                        break;
                    }
                }
                std::vector<int> prev_vars;
                for (int v : acc_map) if (v != 0) prev_vars.push_back(v);
                std::sort(prev_vars.begin(), prev_vars.end());
                prev_vars.erase(std::unique(prev_vars.begin(), prev_vars.end()), prev_vars.end());
                std::vector<int> future_for_start;
                if (k + 1 < front) future_for_start = vars_in_range(block_end, row_end);
                int add_start = first_clause_with_any(run.end, block_end, prev_vars, future_for_start);
                if (add_start < 0) return false;
                std::vector<int> product_vars = vars_in_range(run.start, add_start);
                product_vars.erase(std::remove_if(product_vars.begin(), product_vars.end(), [&](int v) {
                    return first[v] < run.start || first[v] >= add_start;
                }), product_vars.end());
                std::vector<GateGroup> groups;
                if (!scan_adder(add_start, block_end, groups)) return false;
                std::vector<int> future_vars;
                if (k + 1 < front) future_vars = vars_in_range(block_end, row_end);
                std::vector<std::pair<int, int>> term_queries;
                std::vector<int> next_acc(256, 0), prev_map(256, 0);
                for (int pos = 0; pos < static_cast<int>(groups.size()) && pos < 256; ++pos) {
                    std::vector<int> gvars = groups[pos].sum_vars;
                    gvars.insert(gvars.end(), groups[pos].carry_vars.begin(), groups[pos].carry_vars.end());
                    std::sort(gvars.begin(), gvars.end());
                    gvars.erase(std::unique(gvars.begin(), gvars.end()), gvars.end());
                    int best_prev = 0, best_prev_first = static_cast<int>(clauses.size()) + 2;
                    int best_rhs = 0, best_rhs_first = static_cast<int>(clauses.size()) + 2;
                    for (int v : gvars) {
                        if (first[v] < run.start && !is_selector[v] && first[v] < best_prev_first) {
                            best_prev = v;
                            best_prev_first = first[v];
                        }
                        if (contains_sorted(product_vars, v) && first[v] < best_rhs_first) {
                            best_rhs = v;
                            best_rhs_first = first[v];
                        }
                    }
                    if (best_prev) prev_map[pos] = best_prev;
                    if (best_rhs) term_queries.push_back({pos, best_rhs});
                    if (k + 1 < front) {
                        int best_out = 0, best_out_first = static_cast<int>(clauses.size()) + 2;
                        for (int v : groups[pos].sum_vars) {
                            if (contains_sorted(future_vars, v) && first[v] < best_out_first) {
                                best_out = v;
                                best_out_first = first[v];
                            }
                        }
                        if (best_out) next_acc[pos] = best_out;
                    } else {
                        target_bits[pos] = groups[pos].parity;
                    }
                }
                std::vector<int> true_positions;
                if (!propagate_slice_value(run.start, add_start, front + 2 * (k + 1), term_queries, true_positions)) {
                    return false;
                }
                long long num = 0;
                for (int pos : true_positions) {
                    if (pos >= 0 && pos < 62) num |= (1LL << pos);
                }
                C[r][k] = num;
                if (k == 1) {
                    first_term_map = prev_map;
                    have_first_term_map = true;
                }
                acc_map.swap(next_acc);
            }
            if (grid[r][0] >= 0 && have_first_term_map) {
                const Run& run0 = runs[grid[r][0]];
                int first_end = row_end;
                for (int t = 1; t < front; ++t) {
                    if (grid[r][t] >= 0) {
                        first_end = runs[grid[r][t]].start;
                        break;
                    }
                }
                std::vector<std::pair<int, int>> q;
                for (int pos = 0; pos < static_cast<int>(first_term_map.size()); ++pos) {
                    if (first_term_map[pos]) q.push_back({pos, first_term_map[pos]});
                }
                std::vector<int> true_positions;
                if (!propagate_slice_value(run0.start, first_end, front + 2, q, true_positions)) return false;
                long long num = 0;
                for (int pos : true_positions) if (pos >= 0 && pos < 62) num |= (1LL << pos);
                C[r][0] = num;
            }
            long long target = 0;
            for (int pos = 0; pos < static_cast<int>(target_bits.size()) && pos < 62; ++pos) {
                if (target_bits[pos] > 0) target |= (1LL << pos);
            }
            d[r] = target;
        }
        return true;
    }

    bool try_relaxed_row_pair_mitm() {
        if (front < 32 || front > 40) return false;
        std::vector<std::vector<long long>> C;
        std::vector<long long> d;
        if (!recover_relaxed_system(C, d)) return false;
        int rows = static_cast<int>(C.size());
        int n = front;
        int split = n / 2;
        int left_n = split;
        int right_n = n - split;
        struct PairEntry {
            long long a = 0;
            long long b = 0;
            unsigned int mask = 0;
            bool operator<(const PairEntry& other) const {
                if (a != other.a) return a < other.a;
                if (b != other.b) return b < other.b;
                return mask < other.mask;
            }
        };
        std::vector<PairEntry> left;
        left.reserve(1u << left_n);
        std::vector<unsigned long long> candidates;
        const size_t candidate_limit = 256;
        int pairs_tried = 0;
        for (int r0 = 0; r0 < rows; ++r0) {
            for (int r1 = r0 + 1; r1 < rows; ++r1) {
                if (Clock::now() > deadline) {
                    timed_out = true;
                    return false;
                }
                ++pairs_tried;
                left.clear();
                std::vector<long long> s0(1u << left_n, 0), s1(1u << left_n, 0);
                for (unsigned int mask = 1; mask < (1u << left_n); ++mask) {
                    unsigned int lsb = mask & -mask;
                    int j = __builtin_ctz(lsb);
                    unsigned int prev = mask ^ lsb;
                    s0[mask] = s0[prev] + C[r0][j];
                    s1[mask] = s1[prev] + C[r1][j];
                }
                for (unsigned int mask = 0; mask < (1u << left_n); ++mask) {
                    left.push_back({s0[mask], s1[mask], mask});
                }
                std::sort(left.begin(), left.end());
                std::vector<long long> rs0(1u << right_n, 0), rs1(1u << right_n, 0);
                for (unsigned int rm = 0; rm < (1u << right_n); ++rm) {
                    if (rm != 0) {
                        unsigned int lsb = rm & -rm;
                        int jj = __builtin_ctz(lsb);
                        int j = split + jj;
                        unsigned int prev = rm ^ lsb;
                        rs0[rm] = rs0[prev] + C[r0][j];
                        rs1[rm] = rs1[prev] + C[r1][j];
                    }
                    PairEntry probe{d[r0] - rs0[rm], d[r1] - rs1[rm], 0};
                    auto it = std::lower_bound(left.begin(), left.end(), probe);
                    for (; it != left.end() && it->a == probe.a && it->b == probe.b; ++it) {
                        unsigned long long full = it->mask | (static_cast<unsigned long long>(rm) << split);
                        candidates.push_back(full);
                        if (candidates.size() >= candidate_limit) break;
                    }
                    if (candidates.size() >= candidate_limit) break;
                }
                if (!candidates.empty()) {
                    std::sort(candidates.begin(), candidates.end());
                    candidates.erase(std::unique(candidates.begin(), candidates.end()), candidates.end());
                    for (unsigned long long mask : candidates) {
                        if (solve_with_front_mask(mask)) {
                            std::printf("c relaxed row-pair MITM solved using recovered rows %d,%d after %d row pairs and %zu candidates\n",
                                        r0, r1, pairs_tried, candidates.size());
                            return true;
                        }
                    }
                    candidates.clear();
                }
            }
        }
        return false;
    }

    bool solve_with_front_mask(unsigned long long mask) {
        if (!init()) return false;
        for (int j = 0; j < front; ++j) {
            int lit = (mask & (1ULL << j)) ? (j + 1) : -(j + 1);
            if (!enqueue(lit)) return false;
        }
        if (!propagate()) return false;
        if (!complete_aux()) return false;
        return check_model();
    }

    bool try_boundary_mitm() {
        if (front != 30 && front != 40) return false;
        const int split = (front == 40) ? 20 : 14;
        const int base_end = 1 + 4 * front;
        if (static_cast<int>(clauses.size()) <= base_end) return false;

        std::vector<int> selectors(front);
        std::vector<int> selector_col(nvars + 1, -1);
        std::vector<unsigned char> is_selector(nvars + 1, 0);
        for (int j = 0; j < front; ++j) {
            int s = front + 2 * (j + 1);
            if (s > nvars) return false;
            selectors[j] = s;
            selector_col[s] = j;
            is_selector[s] = 1;
        }

        std::vector<int> first(nvars + 1, static_cast<int>(clauses.size()) + 1);
        for (int ci = 0; ci < static_cast<int>(clauses.size()); ++ci) {
            for (int lit : clauses[ci].lits) {
                int v = std::abs(lit);
                if (first[v] > ci) first[v] = ci;
            }
        }

        std::vector<Run> runs = parse_selector_runs(base_end, selector_col);
        if (runs.empty()) return false;
        std::vector<std::vector<int>> grid;
        std::vector<int> cur(front, -1);
        int last_col = -1;
        for (int ri = 0; ri < static_cast<int>(runs.size()); ++ri) {
            if (runs[ri].col <= last_col) {
                grid.push_back(cur);
                std::fill(cur.begin(), cur.end(), -1);
            }
            cur[runs[ri].col] = ri;
            last_col = runs[ri].col;
        }
        grid.push_back(cur);
        int rows = static_cast<int>(grid.size());
        if (rows <= 0 || rows > 64) return false;

        std::vector<int> prefix_ids, suffix_ids, boundary;
        auto add_range = [](std::vector<int>& out, int lo, int hi) {
            for (int i = lo; i < hi; ++i) out.push_back(i);
        };
        add_range(prefix_ids, 0, base_end);
        add_range(suffix_ids, 0, base_end);

        for (int r = 0; r < rows; ++r) {
            int first_run = -1;
            for (int j = 0; j < front; ++j) {
                if (grid[r][j] >= 0) {
                    first_run = grid[r][j];
                    break;
                }
            }
            if (first_run < 0) return false;
            int next_first_start = static_cast<int>(clauses.size());
            if (r + 1 < rows) {
                for (int j = 0; j < front; ++j) {
                    if (grid[r + 1][j] >= 0) {
                        next_first_start = runs[grid[r + 1][j]].start;
                        break;
                    }
                }
            }
            int boundary_start = next_first_start;
            for (int j = split; j < front; ++j) {
                if (grid[r][j] >= 0) {
                    boundary_start = runs[grid[r][j]].start;
                    break;
                }
            }
            add_range(prefix_ids, runs[first_run].start, boundary_start);
            add_range(suffix_ids, boundary_start, next_first_start);

            std::set<int> row_boundary;
            for (int ci = boundary_start; ci < next_first_start; ++ci) {
                for (int lit : clauses[ci].lits) {
                    int v = std::abs(lit);
                    if (v <= nvars && first[v] < boundary_start && !is_selector[v]) {
                        row_boundary.insert(v);
                    }
                }
            }
            if (row_boundary.empty()) return false;
            boundary.insert(boundary.end(), row_boundary.begin(), row_boundary.end());
        }
        if (boundary.empty() || boundary.size() > 2048) return false;

        StaticPropagator prefix_prop, suffix_prop;
        prefix_prop.build(clauses, nvars, prefix_ids);
        suffix_prop.build(clauses, nvars, suffix_ids);

        struct Entry {
            std::string key;
            unsigned int mask = 0;
            bool operator<(const Entry& other) const {
                if (key != other.key) return key < other.key;
                return mask < other.mask;
            }
        };
        std::vector<Entry> left;
        const unsigned int left_count = 1u << split;
        left.reserve(left_count);
        std::string key;

        if (front == 40) {
            unsigned int hc = std::thread::hardware_concurrency();
            int threads = static_cast<int>(std::max(1u, std::min(4u, hc == 0 ? 2u : hc)));
            int left_depth = std::min(split, 5);
            int left_tasks = 1 << left_depth;
            std::vector<std::vector<Entry>> local_left(threads);
            std::atomic<bool> stop{false};

            auto left_worker = [&](int tid) {
                StaticPropagator prop;
                prop.build(clauses, nvars, prefix_ids);
                std::string local_key;
                long long local_nodes = 0;
                std::function<void(int, unsigned int, size_t&)> rec = [&](int pos, unsigned int mask, size_t& qhead_ref) {
                    if (stop.load(std::memory_order_relaxed)) return;
                    if (((++local_nodes) & 4095LL) == 0 && Clock::now() > deadline) {
                        stop.store(true, std::memory_order_relaxed);
                        return;
                    }
                    if (pos == split) {
                        if (prop.key_state(boundary, local_key)) local_left[tid].push_back({local_key, mask});
                        return;
                    }
                    for (int bit = 0; bit <= 1; ++bit) {
                        size_t tm = prop.trail.size(), qm = prop.queue.size(), qhm = qhead_ref;
                        int lit = bit ? (pos + 1) : -(pos + 1);
                        if (prop.assign_state(lit) && prop.propagate_state(qhead_ref)) {
                            rec(pos + 1, mask | (bit ? (1u << pos) : 0u), qhead_ref);
                        }
                        prop.backtrack_state(tm, qm, qhead_ref, qhm);
                    }
                };

                for (int task = tid; task < left_tasks && !stop.load(std::memory_order_relaxed); task += threads) {
                    prop.reset_state();
                    size_t qh = 0;
                    unsigned int mask = 0;
                    bool ok = true;
                    for (int pos = 0; pos < left_depth; ++pos) {
                        int bit = (task >> pos) & 1;
                        mask |= bit ? (1u << pos) : 0u;
                        int lit = bit ? (pos + 1) : -(pos + 1);
                        if (!prop.assign_state(lit)) {
                            ok = false;
                            break;
                        }
                    }
                    if (ok && prop.propagate_state(qh)) rec(left_depth, mask, qh);
                }
            };

            std::vector<std::thread> pool;
            for (int t = 0; t < threads; ++t) pool.emplace_back(left_worker, t);
            for (auto& th : pool) th.join();
            if (stop.load(std::memory_order_relaxed)) {
                timed_out = true;
                return false;
            }
            size_t total = 0;
            for (const auto& v : local_left) total += v.size();
            left.reserve(total);
            for (auto& v : local_left) {
                left.insert(left.end(), std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
            }
            if (left.empty()) return false;
            std::sort(left.begin(), left.end());

            const size_t candidate_limit = 4096;
            std::vector<unsigned long long> candidates;
            std::mutex cand_mutex;
            std::atomic<bool> right_stop{false};
            int right_width = front - split;
            int right_depth = std::min(right_width, 5);
            int right_tasks = 1 << right_depth;

            auto right_worker = [&](int tid) {
                StaticPropagator prop;
                prop.build(clauses, nvars, suffix_ids);
                std::string local_key;
                long long local_nodes = 0;
                std::function<void(int, unsigned int, size_t&)> rec = [&](int rel, unsigned int rmask, size_t& qhead_ref) {
                    if (right_stop.load(std::memory_order_relaxed)) return;
                    if (((++local_nodes) & 4095LL) == 0 && Clock::now() > deadline) {
                        right_stop.store(true, std::memory_order_relaxed);
                        return;
                    }
                    if (rel == right_width) {
                        if (!prop.key_state(boundary, local_key)) return;
                        Entry probe{local_key, 0};
                        auto it = std::lower_bound(left.begin(), left.end(), probe);
                        if (it == left.end() || it->key != local_key) return;
                        std::lock_guard<std::mutex> lock(cand_mutex);
                        for (; it != left.end() && it->key == local_key && candidates.size() < candidate_limit; ++it) {
                            unsigned long long full = it->mask | (static_cast<unsigned long long>(rmask) << split);
                            candidates.push_back(full);
                        }
                        if (candidates.size() >= candidate_limit) right_stop.store(true, std::memory_order_relaxed);
                        return;
                    }
                    int var = split + rel + 1;
                    for (int bit = 0; bit <= 1; ++bit) {
                        size_t tm = prop.trail.size(), qm = prop.queue.size(), qhm = qhead_ref;
                        int lit = bit ? var : -var;
                        if (prop.assign_state(lit) && prop.propagate_state(qhead_ref)) {
                            rec(rel + 1, rmask | (bit ? (1u << rel) : 0u), qhead_ref);
                        }
                        prop.backtrack_state(tm, qm, qhead_ref, qhm);
                    }
                };

                for (int task = tid; task < right_tasks && !right_stop.load(std::memory_order_relaxed); task += threads) {
                    prop.reset_state();
                    size_t qh = 0;
                    unsigned int rmask = 0;
                    bool ok = true;
                    for (int rel = 0; rel < right_depth; ++rel) {
                        int bit = (task >> rel) & 1;
                        rmask |= bit ? (1u << rel) : 0u;
                        int var = split + rel + 1;
                        int lit = bit ? var : -var;
                        if (!prop.assign_state(lit)) {
                            ok = false;
                            break;
                        }
                    }
                    if (ok && prop.propagate_state(qh)) rec(right_depth, rmask, qh);
                }
            };

            pool.clear();
            for (int t = 0; t < threads; ++t) pool.emplace_back(right_worker, t);
            for (auto& th : pool) th.join();
            if (right_stop.load(std::memory_order_relaxed) && Clock::now() > deadline) {
                timed_out = true;
                return false;
            }
            std::sort(candidates.begin(), candidates.end());
            candidates.erase(std::unique(candidates.begin(), candidates.end()), candidates.end());
            for (unsigned long long full : candidates) {
                if (solve_with_front_mask(full)) {
                    std::printf("c parallel boundary MITM solved front vector with %d rows, %zu boundary bits, %zu candidates\n",
                                rows, boundary.size(), candidates.size());
                    return true;
                }
            }
            return false;
        }

        prefix_prop.reset_state();
        size_t pqhead = 0;
        std::function<void(int, unsigned int)> enum_left = [&](int pos, unsigned int mask) {
            if (pos == split) {
                if (prefix_prop.key_state(boundary, key)) left.push_back({key, mask});
                return;
            }
            for (int bit = 0; bit <= 1; ++bit) {
                size_t tm = prefix_prop.trail.size(), qm = prefix_prop.queue.size(), qhm = pqhead;
                int lit = bit ? (pos + 1) : -(pos + 1);
                if (prefix_prop.assign_state(lit) && prefix_prop.propagate_state(pqhead)) {
                    enum_left(pos + 1, mask | (bit ? (1u << pos) : 0u));
                }
                prefix_prop.backtrack_state(tm, qm, pqhead, qhm);
            }
        };
        if (!prefix_prop.propagate_state(pqhead)) return false;
        enum_left(0, 0);
        if (left.empty()) return false;
        std::sort(left.begin(), left.end());

        suffix_prop.reset_state();
        size_t sqhead = 0;
        bool solved = false;
        std::function<void(int, unsigned int)> enum_right = [&](int rel, unsigned int rmask) {
            if (solved) return;
            if (rel == front - split) {
                if (!suffix_prop.key_state(boundary, key)) return;
            Entry probe{key, 0};
            auto it = std::lower_bound(left.begin(), left.end(), probe);
            for (; it != left.end() && it->key == key; ++it) {
                unsigned long long full = it->mask | (static_cast<unsigned long long>(rmask) << split);
                if (solve_with_front_mask(full)) {
                    std::printf("c boundary MITM solved front vector with %d rows and %zu boundary bits\n",
                                rows, boundary.size());
                        solved = true;
                        return;
                }
            }
                return;
            }
            int var = split + rel + 1;
            for (int bit = 0; bit <= 1 && !solved; ++bit) {
                size_t tm = suffix_prop.trail.size(), qm = suffix_prop.queue.size(), qhm = sqhead;
                int lit = bit ? var : -var;
                if (suffix_prop.assign_state(lit) && suffix_prop.propagate_state(sqhead)) {
                    enum_right(rel + 1, rmask | (bit ? (1u << rel) : 0u));
                }
                suffix_prop.backtrack_state(tm, qm, sqhead, qhm);
            }
        };
        if (!suffix_prop.propagate_state(sqhead)) return false;
        enum_right(0, 0);
        return solved;
    }

    bool init() {
        val.assign(nvars + 1, 0);
        level.assign(nvars + 1, 0);
        reason.assign(nvars + 1, -1);
        reason_lit.assign(nvars + 1, 0);
        watches.assign(2 * nvars, {});
        trail.clear();
        q.clear();
        trail_lim.clear();
        q_lim.clear();
        qhead_lim.clear();
        qhead = 0;
        decision_level = 0;
        for (int ci = 0; ci < static_cast<int>(clauses.size()); ++ci) {
            Clause& c = clauses[ci];
            if (c.lits.empty()) return false;
            c.w0 = 0;
            c.w1 = c.lits.size() > 1 ? 1 : 0;
            watches[lit_index(c.lits[c.w0])].push_back(ci);
            if (c.lits.size() > 1) watches[lit_index(c.lits[c.w1])].push_back(ci);
            else if (!enqueue(c.lits[0], ci)) return false;
        }
        build_branch_order();
        return propagate();
    }

    void build_branch_order() {
        std::vector<int> parent(nvars + 1);
        std::iota(parent.begin(), parent.end(), 0);
        auto find = [&](int x) {
            while (parent[x] != x) {
                parent[x] = parent[parent[x]];
                x = parent[x];
            }
            return x;
        };
        auto unite = [&](int a, int b) {
            int ra = find(a), rb = find(b);
            if (ra != rb) parent[rb] = ra;
        };
        std::vector<std::pair<int, int>> bins;
        bins.reserve(clauses.size() / 5);
        for (const Clause& c : clauses) {
            if (c.lits.size() == 2) bins.push_back({c.lits[0], c.lits[1]});
        }
        std::sort(bins.begin(), bins.end());
        auto has = [&](int a, int b) {
            return std::binary_search(bins.begin(), bins.end(), std::make_pair(a, b));
        };
        for (auto [a, b] : bins) {
            if (a < 0 && b > 0 && has(-a, -b)) unite(-a, b);
        }
        std::vector<int> sz(nvars + 1, 0);
        for (int v = 1; v <= nvars; ++v) ++sz[find(v)];
        branch_order.resize(front);
        std::iota(branch_order.begin(), branch_order.end(), 1);
        std::sort(branch_order.begin(), branch_order.end(), [&](int a, int b) {
            int sa = sz[find(a)], sb = sz[find(b)];
            if (sa != sb) return sa > sb;
            return a < b;
        });
    }

    bool propagate() {
        while (qhead < q.size()) {
            int assigned = q[qhead++];
            int false_lit = -assigned;
            auto& wl = watches[lit_index(false_lit)];
            size_t out = 0;
            for (size_t i = 0; i < wl.size(); ++i) {
                int ci = wl[i];
                Clause& c = clauses[ci];
                int wi = (c.lits[c.w0] == false_lit) ? 0 : ((c.lits[c.w1] == false_lit) ? 1 : -1);
                if (wi < 0) {
                    wl[out++] = ci;
                    continue;
                }
                int other_pos = wi == 0 ? c.w1 : c.w0;
                int other_lit = c.lits[other_pos];
                if (lit_value(other_lit) == 1) {
                    wl[out++] = ci;
                    continue;
                }
                bool moved = false;
                for (int np = 0; np < static_cast<int>(c.lits.size()); ++np) {
                    if (np == c.w0 || np == c.w1) continue;
                    if (lit_value(c.lits[np]) != -1) {
                        if (wi == 0) c.w0 = np; else c.w1 = np;
                        watches[lit_index(c.lits[np])].push_back(ci);
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;
                wl[out++] = ci;
                if (lit_value(other_lit) == -1) {
                    ++conflicts;
                    conflict_clause = ci;
                    while (i + 1 < wl.size()) wl[out++] = wl[++i];
                    wl.resize(out);
                    return false;
                }
                if (!enqueue(other_lit, ci)) {
                    ++conflicts;
                    conflict_clause = ci;
                    while (i + 1 < wl.size()) wl[out++] = wl[++i];
                    wl.resize(out);
                    return false;
                }
            }
            wl.resize(out);
            if ((nodes & 4095LL) == 0 && Clock::now() > deadline) {
                timed_out = true;
                return false;
            }
        }
        return true;
    }

    void backtrack(size_t trail_lim, size_t q_lim, size_t qhead_lim) {
        for (size_t i = trail.size(); i > trail_lim; --i) {
            int v = std::abs(trail[i - 1]);
            val[v] = 0;
            reason[v] = -1;
            reason_lit[v] = 0;
            level[v] = 0;
        }
        trail.resize(trail_lim);
        q.resize(q_lim);
        qhead = qhead_lim;
    }

    void explain_false_lit(int lit, std::vector<unsigned char>& seen_var,
                           std::vector<unsigned char>& seen_front,
                           std::vector<int>& learnt) {
        int v = std::abs(lit);
        if (v <= front || reason[v] < 0) {
            if (v <= front && !seen_front[v]) {
                seen_front[v] = 1;
                learnt.push_back(val[v] > 0 ? -v : v);
            }
            return;
        }
        if (seen_var[v]) return;
        seen_var[v] = 1;
        int unit = reason_lit[v];
        const Clause& c = clauses[reason[v]];
        for (int l : c.lits) {
            if (l == unit) continue;
            explain_false_lit(l, seen_var, seen_front, learnt);
            if (learnt.size() > static_cast<size_t>(front)) return;
        }
    }

    void add_learned_from_conflict() {
        if (conflict_clause < 0) return;
        std::vector<unsigned char> seen_var(nvars + 1, 0), seen_front(front + 1, 0);
        std::vector<int> learnt;
        const Clause& c = clauses[conflict_clause];
        for (int l : c.lits) {
            explain_false_lit(l, seen_var, seen_front, learnt);
        }
        conflict_clause = -1;
        std::sort(learnt.begin(), learnt.end(), [](int a, int b) {
            if (std::abs(a) != std::abs(b)) return std::abs(a) < std::abs(b);
            return a < b;
        });
        learnt.erase(std::unique(learnt.begin(), learnt.end()), learnt.end());
        for (size_t i = 1; i < learnt.size(); ++i) {
            if (std::abs(learnt[i - 1]) == std::abs(learnt[i])) {
                return;
            }
        }
        if (learnt.empty()) return;
        Clause nc;
        nc.lits.swap(learnt);
        nc.w0 = 0;
        nc.w1 = nc.lits.size() > 1 ? 1 : 0;
        int idx = static_cast<int>(clauses.size());
        clauses.push_back(std::move(nc));
        watches[lit_index(clauses[idx].lits[clauses[idx].w0])].push_back(idx);
        if (clauses[idx].lits.size() > 1) {
            watches[lit_index(clauses[idx].lits[clauses[idx].w1])].push_back(idx);
        }
    }

    std::vector<int> analyze_conflict() {
        std::vector<int> empty;
        if (conflict_clause < 0) return empty;
        std::vector<unsigned char> seen_var(nvars + 1, 0), seen_front(front + 1, 0);
        std::vector<int> learnt;
        const Clause& c = clauses[conflict_clause];
        for (int l : c.lits) {
            explain_false_lit(l, seen_var, seen_front, learnt);
        }
        conflict_clause = -1;
        std::sort(learnt.begin(), learnt.end(), [](int a, int b) {
            if (std::abs(a) != std::abs(b)) return std::abs(a) < std::abs(b);
            return a < b;
        });
        learnt.erase(std::unique(learnt.begin(), learnt.end()), learnt.end());
        for (size_t i = 1; i < learnt.size(); ++i) {
            if (std::abs(learnt[i - 1]) == std::abs(learnt[i])) {
                return empty;
            }
        }
        return learnt;
    }

    int add_clause(std::vector<int> lits) {
        if (lits.empty()) return -1;
        Clause nc;
        nc.lits.swap(lits);
        nc.w0 = 0;
        nc.w1 = nc.lits.size() > 1 ? 1 : 0;
        int idx = static_cast<int>(clauses.size());
        clauses.push_back(std::move(nc));
        watches[lit_index(clauses[idx].lits[clauses[idx].w0])].push_back(idx);
        if (clauses[idx].lits.size() > 1) {
            watches[lit_index(clauses[idx].lits[clauses[idx].w1])].push_back(idx);
        }
        return idx;
    }

    void new_decision_level() {
        trail_lim.push_back(trail.size());
        q_lim.push_back(q.size());
        qhead_lim.push_back(qhead);
        ++decision_level;
    }

    void backtrack_to(int target) {
        while (decision_level > target) {
            size_t tl = trail_lim.back();
            size_t ql = q_lim.back();
            size_t qhl = qhead_lim.back();
            trail_lim.pop_back();
            q_lim.pop_back();
            qhead_lim.pop_back();
            backtrack(tl, ql, qhl);
            --decision_level;
        }
    }

    int choose_front() const {
        for (int v : branch_order) {
            if (val[v] == 0) return v;
        }
        return 0;
    }

    bool complete_aux() {
        while (true) {
            if (!propagate()) return false;
            int v = 0;
            for (int i = 1; i <= nvars; ++i) {
                if (val[i] == 0) {
                    v = i;
                    break;
                }
            }
            if (v == 0) return true;
            size_t tl = trail.size(), ql = q.size(), qhl = qhead;
            if (enqueue(-v) && complete_aux()) return true;
            backtrack(tl, ql, qhl);
            if (timed_out) return false;
            if (enqueue(v) && complete_aux()) return true;
            backtrack(tl, ql, qhl);
            return false;
        }
    }

    bool search() {
        ++nodes;
        if ((nodes & 4095LL) == 0 && Clock::now() > deadline) {
            timed_out = true;
            return false;
        }
        if (!propagate()) {
            add_learned_from_conflict();
            return false;
        }
        if (timed_out) return false;
        int v = choose_front();
        if (v == 0) return complete_aux();

        size_t tl = trail.size(), ql = q.size(), qhl = qhead;
        int branch[2] = {-v, v};
        if (prefer_true) {
            branch[0] = v;
            branch[1] = -v;
        }
        for (int lit : branch) {
            if (enqueue(lit) && search()) return true;
            backtrack(tl, ql, qhl);
            if (timed_out) return false;
        }
        return false;
    }

    bool search_cdcl() {
        while (true) {
            ++nodes;
            if ((nodes & 4095LL) == 0 && Clock::now() > deadline) {
                timed_out = true;
                return false;
            }
            if (!propagate()) {
                if (timed_out) return false;
                std::vector<int> learnt = analyze_conflict();
                if (learnt.empty()) return false;
                int ci = add_clause(learnt);
                if (ci < 0) return false;

                int max_level = -1;
                int second_level = 0;
                int assert_lit = 0;
                for (int lit : clauses[ci].lits) {
                    int lv = level[std::abs(lit)];
                    if (lv > max_level) {
                        second_level = max_level;
                        max_level = lv;
                        assert_lit = lit;
                    } else if (lv > second_level) {
                        second_level = lv;
                    }
                }
                if (max_level <= 0) return false;
                if (second_level < 0) second_level = 0;
                backtrack_to(second_level);

                bool already_sat = false;
                int unassigned = 0;
                int unit_lit = 0;
                for (int lit : clauses[ci].lits) {
                    signed char lv = lit_value(lit);
                    if (lv == 1) {
                        already_sat = true;
                        break;
                    }
                    if (lv == 0) {
                        ++unassigned;
                        unit_lit = lit;
                    }
                }
                if (!already_sat) {
                    if (unassigned == 1) {
                        if (!enqueue(unit_lit, ci)) return false;
                    } else if (unassigned == 0) {
                        conflict_clause = ci;
                    }
                }
                continue;
            }
            if (timed_out) return false;
            int v = choose_front();
            if (v == 0) return complete_aux();

            new_decision_level();
            int lit = prefer_true ? v : -v;
            if (!enqueue(lit)) return false;
        }
    }

    bool check_model() const {
        for (const Clause& c : clauses) {
            bool sat = false;
            for (int lit : c.lits) {
                signed char x = val[std::abs(lit)];
                if (x != 0 && ((x > 0) == (lit > 0))) {
                    sat = true;
                    break;
                }
            }
            if (!sat) return false;
        }
        return true;
    }
};

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Solver s;
    s.deadline = Clock::now() + std::chrono::seconds(560);
    if (!s.parse(argv[1])) {
        std::puts("c unsupported or malformed CNF");
        std::puts("s UNKNOWN");
        return 0;
    }
    std::printf("c detected leading PEQNP decision vector of %d bits in %d variables, %zu clauses\n",
                s.front, s.nvars, s.clauses.size());
    if (s.front > 40) {
        std::puts("c front vector is wider than the current specialized search budget");
        std::puts("s UNKNOWN");
        return 0;
    }
    if (s.front == 30 && s.nvars > 200000) {
        s.prefer_true = true;
        std::puts("c using true-first phase for large 30-bit instance");
    }
    if (s.try_relaxed_row_pair_mitm()) {
        std::puts("s SATISFIABLE");
        const int per_line = 20;
        for (int base = 1; base <= s.nvars; base += per_line) {
            std::printf("v");
            for (int v = base; v < base + per_line && v <= s.nvars; ++v) {
                int lit = s.val[v] >= 0 ? v : -v;
                std::printf(" %d", lit);
            }
            if (base + per_line > s.nvars) std::printf(" 0");
            std::printf("\n");
        }
        return 10;
    }
    if (s.try_boundary_mitm()) {
        std::puts("s SATISFIABLE");
        const int per_line = 20;
        for (int base = 1; base <= s.nvars; base += per_line) {
            std::printf("v");
            for (int v = base; v < base + per_line && v <= s.nvars; ++v) {
                int lit = s.val[v] >= 0 ? v : -v;
                std::printf(" %d", lit);
            }
            if (base + per_line > s.nvars) std::printf(" 0");
            std::printf("\n");
        }
        return 10;
    }
    if (!s.init()) {
        std::puts("c initial propagation found contradiction; no proof generator is implemented");
        std::puts("s UNKNOWN");
        return 0;
    }
    bool sat = s.search();
    std::printf("c front-vector DPLL nodes=%lld conflicts=%lld timeout=%d\n",
                s.nodes, s.conflicts, s.timed_out ? 1 : 0);
    if (!sat || s.timed_out || !s.check_model()) {
        std::puts("s UNKNOWN");
        return 0;
    }
    std::puts("s SATISFIABLE");
    const int per_line = 20;
    for (int base = 1; base <= s.nvars; base += per_line) {
        std::printf("v");
        for (int v = base; v < base + per_line && v <= s.nvars; ++v) {
            int lit = s.val[v] >= 0 ? v : -v;
            std::printf(" %d", lit);
        }
        if (base + per_line > s.nvars) std::printf(" 0");
        std::printf("\n");
    }
    (void)argv;
    return 10;
}
