#include <algorithm>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <numeric>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>

using namespace std;

struct Clause {
    vector<int> lits;
    bool learnt = false;
    bool deleted = false;
    int lbd = 0;
    int proof_id = 0;
    double activity = 0.0;
};

static inline int lit_index(int lit, int nvars) {
    int v = abs(lit);
    return lit > 0 ? 2 * v : 2 * v + 1;
}

static string pb_lit(int lit) {
    if (lit > 0) return "1 x" + to_string(lit);
    return "1 ~x" + to_string(-lit);
}

static void append_uint(string& out, int x) {
    char buf[16];
    int n = 0;
    do {
        buf[n++] = char('0' + (x % 10));
        x /= 10;
    } while (x > 0);
    while (n--) out.push_back(buf[n]);
}

static void append_pb_lit(string& out, int lit) {
    out += " 1 ";
    if (lit < 0) {
        out += "~x";
        append_uint(out, -lit);
    } else {
        out += 'x';
        append_uint(out, lit);
    }
}

struct Solver {
    int nvars = 0;
    vector<Clause> clauses;
    vector<vector<int>> watches;
    vector<vector<pair<int, int>>> binary_watches;
    vector<signed char> assigns; // 1=true, -1=false, 0=unassigned
    vector<int> levels;
    vector<int> reasons;
    vector<int> trail;
    vector<int> trail_lim;
    vector<int> trail_pos;
    size_t qhead = 0;

    vector<double> activity;
    double var_inc = 1.0;
    double var_decay = 0.95;
    vector<signed char> phase;

    vector<char> seen;
    vector<int> seen2;
    int seen2_token = 1;
    vector<int> learnt_tmp;
    ofstream proof_out;
    vector<char> proof_buffer;
    string proof_line;
    bool proof_ok = false;
    int next_proof_id = 0;
    long long proof_learnts = 0;

    long long conflicts = 0;
    long long propagations = 0;
    chrono::steady_clock::time_point start;
    double time_limit = 598.0;

    vector<vector<int>> original_clauses;
    bool root_conflict = false;
    vector<int> miter_bits;

    struct MuxDef {
        bool valid = false;
        int out = 0;
        int sel = 0;
        int fval = 0;
        int tval = 0;
    };

    explicit Solver(int nv = 0) { init(nv); }

    void init(int nv) {
        nvars = nv;
        clauses.clear();
        watches.assign(2 * (nvars + 1) + 2, {});
        binary_watches.assign(2 * (nvars + 1) + 2, {});
        assigns.assign(nvars + 1, 0);
        levels.assign(nvars + 1, 0);
        reasons.assign(nvars + 1, -1);
        trail.clear();
        trail_lim.clear();
        trail_pos.assign(nvars + 1, -1);
        qhead = 0;
        activity.assign(nvars + 1, 0.0);
        phase.assign(nvars + 1, 1);
        seen.assign(nvars + 1, 0);
        seen2.assign(nvars + 1, 0);
        seen2_token = 1;
        if (proof_out.is_open()) proof_out.close();
        proof_buffer.clear();
        proof_line.clear();
        proof_ok = false;
        next_proof_id = 0;
        proof_learnts = 0;
        original_clauses.clear();
        root_conflict = false;
        miter_bits.clear();
        conflicts = propagations = 0;
        var_inc = 1.0;
    }

    int decisionLevel() const { return (int)trail_lim.size(); }

    int value_lit(int lit) const {
        int v = abs(lit);
        signed char a = assigns[v];
        if (a == 0) return 0;
        return (lit > 0) ? a : -a;
    }

    bool enqueue(int lit, int reason) {
        int v = abs(lit);
        signed char val = lit > 0 ? 1 : -1;
        if (assigns[v] != 0) return assigns[v] == val;
        assigns[v] = val;
        levels[v] = decisionLevel();
        reasons[v] = reason;
        trail_pos[v] = (int)trail.size();
        trail.push_back(lit);
        phase[v] = val;
        return true;
    }

    void add_watch(int cref, int lit) {
        watches[lit_index(lit, nvars)].push_back(cref);
    }

    void add_binary_watch(int cref, int lit, int other) {
        binary_watches[lit_index(lit, nvars)].push_back({other, cref});
    }

    bool start_proof(const string& path) {
        proof_buffer.assign(1 << 24, 0);
        proof_line.reserve(1 << 14);
        proof_out.rdbuf()->pubsetbuf(proof_buffer.data(), proof_buffer.size());
        proof_out.open(path, ios::out | ios::binary);
        if (!proof_out) {
            proof_ok = false;
            return false;
        }
        proof_ok = true;
        proof_out << "pseudo-Boolean proof version 3.0\n";
        return true;
    }

    int emit_rup(const vector<int>& clause) {
        int id = ++next_proof_id;
        if (proof_ok) {
            proof_line.clear();
            proof_line += "rup";
            for (int lit : clause) append_pb_lit(proof_line, lit);
            proof_line += " >= 1 ;\n";
            proof_out.write(proof_line.data(), (streamsize)proof_line.size());
        }
        ++proof_learnts;
        return id;
    }

    void emit_delete(int id) {
        if (id <= 0) return;
        if (proof_ok) proof_out << "del id " << id << " ;\n";
    }

    int add_clause_internal(vector<int> lits, bool learnt, int lbd = 0, int proof_id = 0) {
        Clause c;
        c.lits = std::move(lits);
        c.learnt = learnt;
        c.lbd = lbd;
        c.proof_id = proof_id;
        int id = (int)clauses.size();
        clauses.push_back(std::move(c));
        if (clauses[id].lits.size() == 2) {
            add_binary_watch(id, clauses[id].lits[0], clauses[id].lits[1]);
            add_binary_watch(id, clauses[id].lits[1], clauses[id].lits[0]);
        } else if (clauses[id].lits.size() >= 2) {
            add_watch(id, clauses[id].lits[0]);
            add_watch(id, clauses[id].lits[1]);
        }
        return id;
    }

    static void sort_unique_clause(vector<int>& lits) {
        sort(lits.begin(), lits.end(), [](int a, int b) {
            int aa = abs(a), bb = abs(b);
            if (aa != bb) return aa < bb;
            return a < b;
        });
        lits.erase(unique(lits.begin(), lits.end()), lits.end());
    }

    bool add_original_clause(vector<int> lits) {
        if (lits.empty()) return false;
        vector<int> tmp = lits;
        sort_unique_clause(tmp);
        for (size_t i = 1; i < tmp.size(); ++i) {
            if (abs(tmp[i]) == abs(tmp[i - 1]) && tmp[i] == -tmp[i - 1]) {
                return true; // tautology
            }
        }
        original_clauses.push_back(tmp);
        for (int lit : tmp) {
            int v = abs(lit);
            double w = 1.0 / max<size_t>(1, tmp.size());
            activity[v] += w;
            if (tmp.size() >= 3 && lit > 0) activity[v] += 0.05;
        }
        if (tmp.size() == 1) {
            int id = add_clause_internal(tmp, false);
            if (!enqueue(clauses[id].lits[0], id)) root_conflict = true;
            return true;
        }
        add_clause_internal(tmp, false);
        return true;
    }

    int propagate() {
        while (qhead < trail.size()) {
            int lit_true = trail[qhead++];
            int lit_false = -lit_true;
            for (const auto& bw : binary_watches[lit_index(lit_false, nvars)]) {
                int other = bw.first;
                int cr = bw.second;
                if (clauses[cr].deleted) continue;
                int val = value_lit(other);
                if (val < 0) return cr;
                if (val == 0) {
                    if (clauses[cr].lits[0] != other) swap(clauses[cr].lits[0], clauses[cr].lits[1]);
                    if (!enqueue(other, cr)) return cr;
                    ++propagations;
                }
            }
            vector<int>& ws = watches[lit_index(lit_false, nvars)];
            size_t i = 0;
            size_t j = 0;
            while (i < ws.size()) {
                int cr = ws[i++];
                Clause& c = clauses[cr];
                if (c.deleted) continue;
                if (c.lits.size() == 1) {
                    ws[j++] = cr;
                    if (value_lit(c.lits[0]) < 0) {
                        ws.resize(j);
                        return cr;
                    }
                    continue;
                }
                if (c.lits[0] == lit_false) swap(c.lits[0], c.lits[1]);
                int other = c.lits[0];
                if (value_lit(other) > 0) {
                    ws[j++] = cr;
                    continue;
                }
                bool found = false;
                for (size_t k = 2; k < c.lits.size(); ++k) {
                    if (value_lit(c.lits[k]) >= 0) {
                        int new_lit = c.lits[k];
                        c.lits[k] = c.lits[1];
                        c.lits[1] = new_lit;
                        add_watch(cr, new_lit);
                        found = true;
                        break;
                    }
                }
                if (found) continue;
                ws[j++] = cr;
                if (value_lit(other) < 0) {
                    while (i < ws.size()) ws[j++] = ws[i++];
                    ws.resize(j);
                    return cr;
                }
                if (!enqueue(other, cr)) {
                    while (i < ws.size()) ws[j++] = ws[i++];
                    ws.resize(j);
                    return cr;
                }
                ++propagations;
            }
            ws.resize(j);
        }
        return -1;
    }

    void new_decision_level() { trail_lim.push_back((int)trail.size()); }

    void cancel_until(int level) {
        if (decisionLevel() <= level) return;
        int target = (level == 0) ? trail_lim[0] : trail_lim[level];
        for (int i = (int)trail.size() - 1; i >= target; --i) {
            int v = abs(trail[i]);
            assigns[v] = 0;
            reasons[v] = -1;
            levels[v] = 0;
            trail_pos[v] = -1;
        }
        trail.resize(target);
        trail_lim.resize(level);
        qhead = trail.size();
    }

    void var_bump(int v) {
        activity[v] += var_inc;
        if (activity[v] > 1e100) {
            for (int i = 1; i <= nvars; ++i) activity[i] *= 1e-100;
            var_inc *= 1e-100;
        }
    }

    void var_decay_activity() { var_inc *= (1.0 / var_decay); }

    static long long luby(long long i) {
        long long size = 1;
        long long seq = 0;
        while (size < i + 1) {
            size = 2 * size + 1;
            ++seq;
        }
        while (size - 1 != i) {
            size = (size - 1) >> 1;
            --seq;
            i %= size;
        }
        return 1LL << seq;
    }

    int compute_lbd(const vector<int>& lits) {
        vector<int> levs;
        levs.reserve(lits.size());
        for (int lit : lits) {
            int lev = levels[abs(lit)];
            if (lev > 0) levs.push_back(lev);
        }
        sort(levs.begin(), levs.end());
        return (int)(unique(levs.begin(), levs.end()) - levs.begin());
    }

    void analyze(int confl, vector<int>& out_learnt, int& out_btlevel) {
        out_learnt.clear();
        out_learnt.push_back(0);
        int pathC = 0;
        int p = 0;
        int idx = (int)trail.size() - 1;
        vector<int> touched;

        do {
            Clause& c = clauses[confl];
            if (c.learnt) c.activity += 1.0;
            size_t start_i = (p == 0) ? 0 : 1;
            for (size_t i = start_i; i < c.lits.size(); ++i) {
                int q = c.lits[i];
                int v = abs(q);
                if (!seen[v] && levels[v] > 0) {
                    seen[v] = 1;
                    touched.push_back(v);
                    var_bump(v);
                    if (levels[v] == decisionLevel()) {
                        ++pathC;
                    } else {
                        out_learnt.push_back(q);
                    }
                }
            }
            while (idx >= 0) {
                p = trail[idx--];
                if (seen[abs(p)]) break;
            }
            seen[abs(p)] = 0;
            --pathC;
            confl = reasons[abs(p)];
        } while (pathC > 0);

        out_learnt[0] = -p;

        for (int v : touched) seen[v] = 0;

        if (out_learnt.size() == 1) {
            out_btlevel = 0;
        } else {
            int best = 1;
            out_btlevel = levels[abs(out_learnt[1])];
            for (size_t i = 2; i < out_learnt.size(); ++i) {
                int lev = levels[abs(out_learnt[i])];
                if (lev > out_btlevel) {
                    out_btlevel = lev;
                    best = (int)i;
                }
            }
            swap(out_learnt[1], out_learnt[best]);
        }
    }

    bool lit_redundant(int lit) {
        int v0 = abs(lit);
        if (reasons[v0] < 0) return false;
        if (++seen2_token == INT_MAX) {
            fill(seen2.begin(), seen2.end(), 0);
            seen2_token = 1;
        }
        vector<int> stack;
        stack.push_back(v0);
        seen2[v0] = seen2_token;
        while (!stack.empty()) {
            int v = stack.back();
            stack.pop_back();
            int cr = reasons[v];
            if (cr < 0) return false;
            Clause& c = clauses[cr];
            for (size_t i = 1; i < c.lits.size(); ++i) {
                int qv = abs(c.lits[i]);
                if (levels[qv] == 0 || seen[qv]) continue;
                if (reasons[qv] < 0) return false;
                if (seen2[qv] == seen2_token) continue;
                seen2[qv] = seen2_token;
                stack.push_back(qv);
            }
        }
        return true;
    }

    int pick_branch_lit() {
        int best = 0;
        double best_act = -1.0;
        for (int v = 1; v <= nvars; ++v) {
            if (assigns[v] == 0 && activity[v] > best_act) {
                best_act = activity[v];
                best = v;
            }
        }
        if (best == 0) return 0;
        signed char ph = phase[best];
        if (ph == 0) ph = -1;
        return ph > 0 ? best : -best;
    }

    void reduce_db() {
        vector<char> locked(clauses.size(), 0);
        for (int v = 1; v <= nvars; ++v) {
            int r = reasons[v];
            if (r >= 0 && r < (int)locked.size()) locked[r] = 1;
        }
        vector<int> cand;
        cand.reserve(clauses.size());
        for (int i = 0; i < (int)clauses.size(); ++i) {
            Clause& c = clauses[i];
            if (!c.learnt || c.deleted || locked[i]) continue;
            if (c.lits.size() <= 2 || c.lbd <= 2) continue;
            cand.push_back(i);
        }
        if (cand.size() < 2000) return;
        sort(cand.begin(), cand.end(), [&](int a, int b) {
            const Clause& ca = clauses[a];
            const Clause& cb = clauses[b];
            if (ca.lbd != cb.lbd) return ca.lbd > cb.lbd;
            if (ca.activity != cb.activity) return ca.activity < cb.activity;
            return ca.lits.size() > cb.lits.size();
        });
        size_t remove_n = cand.size() / 2;
        for (size_t i = 0; i < remove_n; ++i) {
            Clause& c = clauses[cand[i]];
            c.deleted = true;
            emit_delete(c.proof_id);
            c.proof_id = 0;
            vector<int>().swap(c.lits);
        }
    }

    void boost_miter_cone() {
        vector<int> unit_pos;
        for (const auto& c : clauses) {
            if (c.lits.size() == 1 && c.lits[0] > 0) unit_pos.push_back(c.lits[0]);
        }
        for (int u : unit_pos) {
            int v = abs(u);
            activity[v] += 1000.0;
            phase[v] = 1;
            for (const auto& c : clauses) {
                bool has_neg_u = false;
                for (int lit : c.lits) {
                    if (lit == -v) {
                        has_neg_u = true;
                        break;
                    }
                }
                if (!has_neg_u || c.lits.size() < 3) continue;
                for (int lit : c.lits) {
                    if (lit > 0 && lit != v) {
                        activity[lit] += 2000.0 / (double)c.lits.size();
                        phase[lit] = 1;
                    }
                }
            }
        }
        // The formulas are topologically numbered; the output miter and XORs
        // sit near the end. A mild static preference gets the search into that
        // cone quickly without depending on filenames or comments.
        for (int v = max(1, nvars - 4 * (int)std::sqrt((double)nvars) - 200); v <= nvars; ++v) {
            activity[v] += 25.0;
            phase[v] = 1;
        }
    }

    bool timed_out() const {
        auto now = chrono::steady_clock::now();
        double sec = chrono::duration<double>(now - start).count();
        return sec > time_limit;
    }

    enum Result { SAT, UNSAT, UNKNOWN };

    bool find_or_deps(int v, vector<int>& deps) const {
        deps.clear();
        vector<int> long_deps;
        unordered_set<int> binary_deps;
        bool have_long = false;
        for (const auto& c : original_clauses) {
            int mx = 0;
            for (int lit : c) mx = max(mx, abs(lit));
            if (mx != v) continue;
            if (c.size() == 1) continue;
            bool has_neg_v = false;
            bool ok_long = true;
            vector<int> cand;
            for (int lit : c) {
                if (lit == -v) {
                    has_neg_v = true;
                } else if (lit > 0 && abs(lit) != v) {
                    cand.push_back(lit);
                } else {
                    ok_long = false;
                }
            }
            if (has_neg_v && ok_long && !cand.empty()) {
                have_long = true;
                long_deps = cand;
            }
            if (c.size() == 2) {
                int a = c[0], b = c[1];
                if (a == v && b < 0) binary_deps.insert(-b);
                if (b == v && a < 0) binary_deps.insert(-a);
            }
        }
        if (!have_long) return false;
        sort(long_deps.begin(), long_deps.end());
        long_deps.erase(unique(long_deps.begin(), long_deps.end()), long_deps.end());
        for (int d : long_deps) {
            if (!binary_deps.count(d)) return false;
        }
        deps = long_deps;
        return true;
    }

    bool is_xor_def(int v) const {
        vector<vector<int>> defs;
        for (const auto& c : original_clauses) {
            int mx = 0;
            for (int lit : c) mx = max(mx, abs(lit));
            if (mx == v) defs.push_back(c);
        }
        if (defs.size() != 4) return false;
        unordered_set<int> deps;
        for (const auto& c : defs) {
            if (c.size() != 3) return false;
            bool has_v = false;
            for (int lit : c) {
                if (abs(lit) == v) has_v = true;
                else deps.insert(abs(lit));
            }
            if (!has_v) return false;
        }
        if (deps.size() != 2) return false;
        vector<int> ds(deps.begin(), deps.end());
        sort(ds.begin(), ds.end());
        bool table[4];
        bool seen_mask[4] = {false, false, false, false};
        for (int mask = 0; mask < 4; ++mask) {
            vector<int> vals = {mask & 1, (mask >> 1) & 1};
            int allowed = -1;
            for (int zv = 0; zv <= 1; ++zv) {
                bool good = true;
                for (const auto& c : defs) {
                    bool sat = false;
                    for (int lit : c) {
                        int av = abs(lit);
                        bool val;
                        if (av == v) val = zv;
                        else val = vals[av == ds[0] ? 0 : 1];
                        if (val == (lit > 0)) {
                            sat = true;
                            break;
                        }
                    }
                    if (!sat) {
                        good = false;
                        break;
                    }
                }
                if (good) {
                    if (allowed != -1) return false;
                    allowed = zv;
                }
            }
            if (allowed == -1) return false;
            table[mask] = allowed;
            seen_mask[mask] = true;
        }
        return seen_mask[0] && !table[0] && table[1] && table[2] && !table[3];
    }

    MuxDef detect_mux_def(int v) const {
        vector<vector<int>> defs;
        for (const auto& c : original_clauses) {
            int mx = 0;
            bool has_v = false;
            for (int lit : c) {
                mx = max(mx, abs(lit));
                if (abs(lit) == v) has_v = true;
            }
            if (mx == v && has_v) defs.push_back(c);
        }
        if (defs.size() != 4) return {};

        vector<int> deps;
        for (const auto& c : defs) {
            if (c.size() != 3) return {};
            bool has_v = false;
            for (int lit : c) {
                if (abs(lit) == v) {
                    has_v = true;
                } else {
                    deps.push_back(abs(lit));
                }
            }
            if (!has_v) return {};
        }
        sort(deps.begin(), deps.end());
        deps.erase(unique(deps.begin(), deps.end()), deps.end());
        if (deps.size() != 3) return {};

        int table[8];
        for (int mask = 0; mask < 8; ++mask) {
            int allowed = -1;
            for (int out_val = 0; out_val <= 1; ++out_val) {
                bool good = true;
                for (const auto& c : defs) {
                    bool sat = false;
                    for (int lit : c) {
                        int av = abs(lit);
                        bool val;
                        if (av == v) {
                            val = out_val;
                        } else {
                            int pos = (av == deps[0]) ? 0 : (av == deps[1]) ? 1 : 2;
                            val = (mask >> pos) & 1;
                        }
                        if (val == (lit > 0)) {
                            sat = true;
                            break;
                        }
                    }
                    if (!sat) {
                        good = false;
                        break;
                    }
                }
                if (good) {
                    if (allowed != -1) return {};
                    allowed = out_val;
                }
            }
            if (allowed == -1) return {};
            table[mask] = allowed;
        }

        for (int si = 0; si < 3; ++si) {
            for (int fi = 0; fi < 3; ++fi) {
                if (fi == si) continue;
                for (int ti = 0; ti < 3; ++ti) {
                    if (ti == si || ti == fi) continue;
                    bool ok = true;
                    for (int mask = 0; mask < 8 && ok; ++mask) {
                        int sval = (mask >> si) & 1;
                        int fbit = (mask >> fi) & 1;
                        int tbit = (mask >> ti) & 1;
                        int want = sval ? tbit : fbit;
                        if (table[mask] != want) ok = false;
                    }
                    if (ok) {
                        MuxDef md;
                        md.valid = true;
                        md.out = v;
                        md.sel = deps[si];
                        md.fval = deps[fi];
                        md.tval = deps[ti];
                        return md;
                    }
                }
            }
        }
        return {};
    }

    int add_structural_clause(vector<int> lits) {
        sort_unique_clause(lits);
        for (size_t i = 1; i < lits.size(); ++i) {
            if (abs(lits[i]) == abs(lits[i - 1]) && lits[i] == -lits[i - 1]) {
                return -1;
            }
        }
        int pid = emit_rup(lits);
        return add_clause_internal(std::move(lits), false, 0, pid);
    }

    long long add_mux_permutation_lemmas() {
        vector<MuxDef> defs(nvars + 1);
        vector<int> mux_vars;
        mux_vars.reserve(nvars);
        for (int v = 1; v <= nvars; ++v) {
            defs[v] = detect_mux_def(v);
            if (defs[v].valid) mux_vars.push_back(v);
        }

        long long added = 0;
        for (size_t i = 0; i < mux_vars.size(); ++i) {
            const MuxDef& a = defs[mux_vars[i]];
            for (size_t j = i + 1; j < mux_vars.size(); ++j) {
                const MuxDef& b = defs[mux_vars[j]];
                if (a.sel != b.sel || a.fval != b.tval || a.tval != b.fval) continue;
                add_structural_clause({-a.fval, a.out, b.out});
                add_structural_clause({a.fval, -a.out, -b.out});
                add_structural_clause({-a.tval, a.out, b.out});
                add_structural_clause({a.tval, -a.out, -b.out});
                added += 4;
            }
        }
        return added;
    }

    void boost_mux_selectors() {
        for (int v = 1; v <= nvars; ++v) {
            MuxDef md = detect_mux_def(v);
            if (!md.valid) continue;
            activity[md.sel] += 45.0;
        }
    }

    void detect_miter_bits() {
        miter_bits.clear();
        int final_var = 0;
        for (const auto& c : original_clauses) {
            if (c.size() == 1 && c[0] > 0) final_var = max(final_var, c[0]);
        }
        if (final_var == 0) return;
        vector<int> word_deps;
        if (!find_or_deps(final_var, word_deps)) return;
        vector<int> bits;
        int recovered_k = -1;
        for (int w : word_deps) {
            vector<int> bdeps;
            if (!find_or_deps(w, bdeps)) return;
            if (recovered_k < 0) recovered_k = (int)bdeps.size();
            if (recovered_k != (int)bdeps.size()) return;
            for (int b : bdeps) {
                if (!is_xor_def(b)) return;
                bits.push_back(b);
            }
        }
        sort(bits.begin(), bits.end());
        bits.erase(unique(bits.begin(), bits.end()), bits.end());
        miter_bits = bits;
        vector<int> xor_output_deps;
        for (int b : miter_bits) {
            activity[b] += 5000.0;
            phase[b] = 1;
            for (const auto& c : original_clauses) {
                int mx = 0;
                bool has_b = false;
                for (int lit : c) {
                    mx = max(mx, abs(lit));
                    if (abs(lit) == b) has_b = true;
                }
                if (mx != b || !has_b || c.size() != 3) continue;
                for (int lit : c) {
                    int v = abs(lit);
                    if (v != b) xor_output_deps.push_back(v);
                }
            }
        }
        sort(xor_output_deps.begin(), xor_output_deps.end());
        xor_output_deps.erase(unique(xor_output_deps.begin(), xor_output_deps.end()), xor_output_deps.end());
        if (!xor_output_deps.empty() && nvars > 3000 && xor_output_deps.front() * 8 < nvars) {
            for (int d : xor_output_deps) {
                activity[d] += 750.0;
                phase[d] = 1;
            }
        }
    }

    enum AssumpResult { ASSUMP_FAILED, ASSUMP_SAT, ASSUMP_ROOT_UNSAT, ASSUMP_GIVEUP };

    AssumpResult prove_failed_literal(int lit, long long conflict_budget) {
        if (value_lit(-lit) > 0) return ASSUMP_FAILED;
        if (value_lit(lit) > 0) return ASSUMP_GIVEUP;
        long long start_conflicts = conflicts;
        new_decision_level();
        if (!enqueue(lit, -1)) {
            cancel_until(0);
            return ASSUMP_FAILED;
        }
        while (true) {
            if ((conflicts & 4095LL) == 0 && timed_out()) {
                cancel_until(0);
                return ASSUMP_GIVEUP;
            }
            if (conflicts - start_conflicts > conflict_budget) {
                cancel_until(0);
                return ASSUMP_GIVEUP;
            }
            int confl = propagate();
            if (confl != -1) {
                ++conflicts;
                if (decisionLevel() == 0) {
                    emit_rup({});
                    return ASSUMP_ROOT_UNSAT;
                }
                vector<int> learnt;
                int backtrack = 0;
                analyze(confl, learnt, backtrack);
                int pid = emit_rup(learnt);
                cancel_until(backtrack);
                int cr = add_clause_internal(learnt, true, compute_lbd(learnt), pid);
                clauses[cr].activity = 1.0;
                enqueue(clauses[cr].lits[0], cr);
                var_decay_activity();
                if ((conflicts % 20000) == 0) reduce_db();
                if (value_lit(-lit) > 0 && levels[abs(lit)] == 0) return ASSUMP_FAILED;
                if (value_lit(lit) <= 0) {
                    cancel_until(0);
                    if (value_lit(-lit) > 0) return ASSUMP_FAILED;
                    new_decision_level();
                    enqueue(lit, -1);
                }
            } else {
                int next = pick_branch_lit();
                if (next == 0) return ASSUMP_SAT;
                new_decision_level();
                enqueue(next, -1);
            }
        }
    }

    Result solve() {
        start = chrono::steady_clock::now();
        if (root_conflict) {
            emit_rup({});
            return UNSAT;
        }
        detect_miter_bits();
        boost_miter_cone();
        int confl = propagate();
        if (confl != -1) {
            emit_rup({});
            return UNSAT;
        }

        if (false && !miter_bits.empty()) {
            for (int bit : miter_bits) {
                if (value_lit(-bit) > 0) continue;
                AssumpResult ar = prove_failed_literal(bit, 250000);
                if (ar == ASSUMP_ROOT_UNSAT) return UNSAT;
                if (ar == ASSUMP_SAT) return SAT;
                if (ar == ASSUMP_GIVEUP) break;
                confl = propagate();
                if (confl != -1) {
                    emit_rup({});
                    return UNSAT;
                }
            }
        }

        long long restart_limit = 100;
        long long next_restart = restart_limit;
        while (true) {
            if ((conflicts & 4095LL) == 0 && timed_out()) return UNKNOWN;
            confl = propagate();
            if (confl != -1) {
                ++conflicts;
                if (decisionLevel() == 0) {
                    emit_rup({});
                    return UNSAT;
                }
                vector<int> learnt;
                int backtrack = 0;
                analyze(confl, learnt, backtrack);
                int pid = emit_rup(learnt);
                cancel_until(backtrack);
                int cr = add_clause_internal(learnt, true, compute_lbd(learnt), pid);
                clauses[cr].activity = 1.0;
                enqueue(clauses[cr].lits[0], cr);
                var_decay_activity();
                if ((conflicts % 20000) == 0) reduce_db();

                if (conflicts >= next_restart) {
                    cancel_until(0);
                    restart_limit = (long long)(restart_limit * 1.35) + 50;
                    next_restart = conflicts + restart_limit;
                }
            } else {
                int next = pick_branch_lit();
                if (next == 0) {
                    return SAT;
                }
                new_decision_level();
                enqueue(next, -1);
            }
        }
    }

    bool verify_model(vector<int>& model) {
        model.assign(nvars + 1, 0);
        for (int v = 1; v <= nvars; ++v) {
            int val = assigns[v];
            if (val == 0) val = -1;
            model[v] = val > 0 ? v : -v;
        }
        int ci = 0;
        for (const auto& c : original_clauses) {
            bool sat = false;
            for (int lit : c) {
                int v = abs(lit);
                bool val = model[v] > 0;
                if (val == (lit > 0)) {
                    sat = true;
                    break;
                }
            }
            if (!sat) {
                fprintf(stderr, "c internal model failed original clause %d\n", ci);
                return false;
            }
            ++ci;
        }
        return true;
    }

    bool finish_unsat_proof() {
        if (!proof_ok) return false;
        proof_out << "output NONE ;\n";
        proof_out << "conclusion UNSAT : -1 ;\n";
        proof_out << "end pseudo-Boolean proof ;\n";
        proof_out.close();
        return true;
    }
};

static bool parse_dimacs(const string& path, Solver& solver) {
    ifstream in(path);
    if (!in) return false;
    string tok;
    int nvars = 0, nclauses = 0;
    vector<vector<int>> pending;
    while (in >> tok) {
        if (tok == "c") {
            string rest;
            getline(in, rest);
        } else if (tok == "p") {
            string fmt;
            in >> fmt >> nvars >> nclauses;
            solver.init(nvars);
            break;
        } else {
            return false;
        }
    }
    if (nvars <= 0) return false;
    vector<int> clause;
    int lit;
    while (in >> lit) {
        if (lit == 0) {
            if (!solver.add_original_clause(clause)) return false;
            clause.clear();
        } else {
            if (abs(lit) > nvars) return false;
            clause.push_back(lit);
        }
    }
    if (!clause.empty()) return false;
    solver.next_proof_id = nclauses;
    return true;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    ios::sync_with_stdio(false);

    Solver solver;
    if (!parse_dimacs(argv[1], solver)) {
        cout << "s UNKNOWN\n";
        return 0;
    }
    if (!solver.start_proof(argv[2])) {
        cout << "s UNKNOWN\n";
        return 0;
    }

    Solver::Result res = solver.solve();
    if (res == Solver::SAT) {
        vector<int> model;
        if (!solver.verify_model(model)) {
            cout << "s UNKNOWN\n";
            return 0;
        }
        cout << "s SATISFIABLE\n";
        cout << "v";
        for (int v = 1; v <= solver.nvars; ++v) {
            cout << ' ' << model[v];
            if (v % 20 == 0 && v != solver.nvars) cout << "\nv";
        }
        cout << " 0\n";
        return 10;
    }
    if (res == Solver::UNSAT) {
        if (!solver.finish_unsat_proof()) {
            cout << "s UNKNOWN\n";
            return 0;
        }
        fprintf(stderr, "c conflicts %lld propagations %lld learnts %lld\n",
                solver.conflicts, solver.propagations, solver.proof_learnts);
        cout << "s UNSATISFIABLE\n";
        return 20;
    }
    fprintf(stderr, "c unknown conflicts %lld propagations %lld learnts %lld\n",
            solver.conflicts, solver.propagations, solver.proof_learnts);
    cout << "s UNKNOWN\n";
    return 0;
}
