#include <algorithm>
#include <array>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <fstream>
#include <iostream>
#include <numeric>
#include <queue>
#include <string>
#include <unordered_set>
#include <vector>

using Clock = std::chrono::steady_clock;

struct XorShift {
    uint64_t s;
    explicit XorShift(uint64_t seed = 88172645463325252ull) : s(seed ? seed : 1) {}
    uint64_t next() {
        uint64_t x = s;
        x ^= x << 7;
        x ^= x >> 9;
        s = x;
        return x;
    }
    int randint(int n) { return (int)(next() % (uint64_t)n); }
    bool chance(int num, int den) { return (int)(next() % (uint64_t)den) < num; }
};

struct Clause {
    int off = 0;
    int len = 0;
};

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

static inline bool lit_true(int lit, const std::vector<uint8_t>& val) {
    bool x = val[std::abs(lit)];
    return lit > 0 ? x : !x;
}

struct Solver {
    int nvars = 0;
    int nclauses = 0;
    int len4_clauses = 0;
    std::vector<Clause> clauses;
    std::vector<int> lits;
    std::vector<std::vector<int>> occ;
    std::vector<int8_t> fixed;
    std::vector<uint8_t> val;
    std::vector<uint16_t> satcnt;
    std::vector<int> unsat;
    std::vector<int> unsat_pos;
    XorShift rng;

    bool parse(const char* path) {
        std::ifstream in(path);
        if (!in) return false;
        std::string tok;
        int declared_m = 0;
        while (in >> tok) {
            if (tok == "c") {
                std::string rest;
                std::getline(in, rest);
            } else if (tok == "p") {
                std::string cnf;
                in >> cnf >> nvars >> declared_m;
                clauses.reserve(declared_m);
                fixed.assign(nvars + 1, -1);
                occ.assign((nvars + 1) * 2, {});
            } else {
                int lit = std::stoi(tok);
                std::vector<int> cl;
                while (lit != 0) {
                    cl.push_back(lit);
                    in >> lit;
                }
                if (cl.empty()) return false;
                if ((int)cl.size() == 1) {
                    int v = std::abs(cl[0]);
                    int b = cl[0] > 0 ? 1 : 0;
                    if (fixed[v] != -1 && fixed[v] != b) return false;
                    fixed[v] = (int8_t)b;
                }
                if ((int)cl.size() == 4) ++len4_clauses;
                Clause c{(int)lits.size(), (int)cl.size()};
                int ci = (int)clauses.size();
                clauses.push_back(c);
                for (int l : cl) {
                    lits.push_back(l);
                    if (std::abs(l) <= nvars) occ[lit_index(l)].push_back(ci);
                }
            }
        }
        nclauses = (int)clauses.size();
        if (declared_m && declared_m != nclauses) {
            std::fprintf(stderr, "c warning declared clauses %d parsed %d\n", declared_m, nclauses);
        }
        val.assign(nvars + 1, 0);
        satcnt.assign(nclauses, 0);
        unsat_pos.assign(nclauses, -1);
        uint64_t seed = 1469598103934665603ull;
        seed ^= (uint64_t)nvars + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);
        seed ^= (uint64_t)nclauses + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);
        for (int l : lits) seed = (seed ^ (uint64_t)(uint32_t)l) * 1099511628211ull;
        rng = XorShift(seed);
        return true;
    }

    void add_unsat(int ci) {
        if (unsat_pos[ci] >= 0) return;
        unsat_pos[ci] = (int)unsat.size();
        unsat.push_back(ci);
    }

    void remove_unsat(int ci) {
        int p = unsat_pos[ci];
        if (p < 0) return;
        int last = unsat.back();
        unsat[p] = last;
        unsat_pos[last] = p;
        unsat.pop_back();
        unsat_pos[ci] = -1;
    }

    void initialize(int restart) {
        unsat.clear();
        std::fill(unsat_pos.begin(), unsat_pos.end(), -1);
        for (int v = 1; v <= nvars; ++v) {
            if (fixed[v] != -1) val[v] = (uint8_t)fixed[v];
            else if (restart == 0) val[v] = 0;
            else val[v] = (uint8_t)(rng.next() & 1);
        }
        if (restart == 0) {
            // Sparse algebraic encodings are often close to the all-zero point,
            // but a small amount of noise avoids deterministic plateaus.
            for (int v = 1; v <= nvars; ++v) {
                if (fixed[v] == -1 && rng.chance(1, 64)) val[v] ^= 1;
            }
        }
        for (int ci = 0; ci < nclauses; ++ci) {
            int s = 0;
            Clause c = clauses[ci];
            for (int i = 0; i < c.len; ++i) s += lit_true(lits[c.off + i], val);
            satcnt[ci] = (uint16_t)s;
            if (s == 0) add_unsat(ci);
        }
    }

    int break_count(int v) const {
        int b = 0;
        int lit_now_true = val[v] ? v : -v;
        for (int ci : occ[lit_index(lit_now_true)]) {
            if (satcnt[ci] == 1) ++b;
        }
        return b;
    }

    int make_count(int v) const {
        int m = 0;
        int lit_after_true = val[v] ? -v : v;
        for (int ci : occ[lit_index(lit_after_true)]) {
            if (satcnt[ci] == 0) ++m;
        }
        return m;
    }

    void flip(int v) {
        int lit_becomes_false = val[v] ? v : -v;
        int lit_becomes_true = -lit_becomes_false;
        for (int ci : occ[lit_index(lit_becomes_false)]) {
            uint16_t before = satcnt[ci]--;
            if (before == 1) add_unsat(ci);
        }
        val[v] ^= 1;
        for (int ci : occ[lit_index(lit_becomes_true)]) {
            uint16_t before = satcnt[ci]++;
            if (before == 0) remove_unsat(ci);
        }
    }

    int choose_var() {
        int ci = unsat[rng.randint((int)unsat.size())];
        Clause c = clauses[ci];
        int choices[8];
        int nchoices = 0;
        for (int i = 0; i < c.len; ++i) {
            int v = std::abs(lits[c.off + i]);
            if (fixed[v] == -1) choices[nchoices++] = v;
        }
        if (nchoices == 0) return 0;
        if (rng.chance(1, 100)) return choices[rng.randint(nchoices)];
        int best[8], nbest = 0, best_break = 1 << 30, best_make = -1;
        for (int i = 0; i < nchoices; ++i) {
            int v = choices[i];
            int b = break_count(v);
            int m = make_count(v);
            if (b < best_break || (b == best_break && m > best_make)) {
                best_break = b;
                best_make = m;
                nbest = 0;
                best[nbest++] = v;
            } else if (b == best_break && m == best_make) {
                best[nbest++] = v;
            }
        }
        if (best_break > 0 && rng.chance(8, 100)) return choices[rng.randint(nchoices)];
        return best[rng.randint(nbest)];
    }

    bool verify() const {
        for (const Clause& c : clauses) {
            bool ok = false;
            for (int i = 0; i < c.len; ++i) {
                if (lit_true(lits[c.off + i], val)) {
                    ok = true;
                    break;
                }
            }
            if (!ok) return false;
        }
        return true;
    }

    bool search(double seconds) {
        auto deadline = Clock::now() + std::chrono::milliseconds((int)(seconds * 1000));
        long long flips = 0;
        for (int restart = 0; Clock::now() < deadline; ++restart) {
            initialize(restart);
            long long max_flips = std::max<long long>(2000000, 80ll * (long long)nclauses);
            for (long long step = 0; step < max_flips; ++step) {
                if (unsat.empty()) return verify();
                if ((++flips & 8191) == 0 && Clock::now() >= deadline) return false;
                int v = choose_var();
                if (v == 0) break;
                flip(v);
            }
            std::printf("c restart %d unsat %zu flips %lld\n", restart, unsat.size(), flips);
            std::fflush(stdout);
        }
        return false;
    }

    int brent_rank_guess() const {
        // In this family the XOR-3 Tseitin blocks contribute
        // 8 * 729 * ((r - 1) / 2) four-literal clauses.
        if (len4_clauses % (8 * 729) != 0) return -1;
        int blocks_per_equation = len4_clauses / (8 * 729);
        return 2 * blocks_per_equation + 1;
    }

    void print_model() const {
        std::printf("s SATISFIABLE\n");
        int col = 0;
        std::printf("v ");
        for (int v = 1; v <= nvars; ++v) {
            int lit = val[v] ? v : -v;
            std::printf("%d ", lit);
            if (++col == 12 && v != nvars) {
                std::printf("\nv ");
                col = 0;
            }
        }
        std::printf("0\n");
    }
};

struct CDCLClause {
    std::vector<int> lits;
    int watch0 = 0;
    int watch1 = 0;
    int lbd = 0;
    bool learnt = false;
    bool deleted = false;
};

struct ProofCDCL {
    int nvars = 0;
    std::vector<CDCLClause> clauses;
    std::vector<std::vector<int>> watches;
    std::vector<int8_t> assigns;
    std::vector<int8_t> phase;
    std::vector<int> levels;
    std::vector<int> reasons;
    std::vector<int> trail;
    std::vector<int> trail_lim;
    int qhead = 0;
    std::vector<double> activity;
    double var_inc = 1.0;
    double var_decay = 0.95;
    std::priority_queue<std::pair<double, int>> heap;
    std::vector<uint8_t> seen;
    std::vector<uint8_t> decision_allowed;
    std::vector<int> level_seen;
    std::ofstream proof;
    Clock::time_point deadline;
    int original_clause_count = 0;
    int level_stamp = 1;
    long long conflicts = 0;
    long long learned = 0;
    long long deleted_clauses = 0;
    bool order_ascending = true;
    bool use_restarts = true;
    int initial_phase = 0;
    int reduce_interval = 100000;
    int protect_recent = 100000;
    int keep_lbd = 4;
    int keep_size = 12;
    int probe_limit = 0;

    explicit ProofCDCL(const Solver& s) : nvars(s.nvars) {
        if (const char* e = std::getenv("CDCL_ORDER")) order_ascending = std::strcmp(e, "desc") != 0;
        if (const char* e = std::getenv("CDCL_RESTARTS")) use_restarts = std::atoi(e) != 0;
        if (const char* e = std::getenv("CDCL_PHASE")) initial_phase = std::atoi(e) ? 1 : 0;
        if (const char* e = std::getenv("CDCL_REDUCE_INTERVAL")) reduce_interval = std::max(1000, std::atoi(e));
        if (const char* e = std::getenv("CDCL_PROTECT_RECENT")) protect_recent = std::max(1000, std::atoi(e));
        if (const char* e = std::getenv("CDCL_KEEP_LBD")) keep_lbd = std::max(1, std::atoi(e));
        if (const char* e = std::getenv("CDCL_KEEP_SIZE")) keep_size = std::max(2, std::atoi(e));
        if (const char* e = std::getenv("CDCL_PROBE_LIMIT")) probe_limit = std::max(0, std::atoi(e));
        clauses.reserve(s.clauses.size() + 1024);
        watches.assign((nvars + 1) * 2, {});
        assigns.assign(nvars + 1, -1);
        phase.assign(nvars + 1, (int8_t)initial_phase);
        levels.assign(nvars + 1, 0);
        reasons.assign(nvars + 1, -1);
        activity.assign(nvars + 1, 0.0);
        seen.assign(nvars + 1, 0);
        decision_allowed.assign(nvars + 1, 1);
        level_seen.assign(nvars + 2, 0);

        for (const Clause& c : s.clauses) {
            CDCLClause cc;
            cc.lits.assign(s.lits.begin() + c.off, s.lits.begin() + c.off + c.len);
            clauses.push_back(std::move(cc));
            for (int lit : clauses.back().lits) activity[std::abs(lit)] += 1.0;
        }
        original_clause_count = (int)clauses.size();
        detect_primary_decisions(s);
        for (int v = 1; v <= nvars; ++v) {
            if (decision_allowed[v]) heap.push({activity[v], heap_key(v)});
        }
    }

    int heap_key(int v) const {
        return order_ascending ? -v : v;
    }

    int heap_var(int key) const {
        return order_ascending ? -key : key;
    }

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

    int lit_value(int lit) const {
        int8_t a = assigns[std::abs(lit)];
        if (a < 0) return -1;
        bool val = lit > 0 ? a : !a;
        return val ? 1 : 0;
    }

    bool enqueue(int lit, int reason) {
        int v = std::abs(lit);
        int8_t want = lit > 0 ? 1 : 0;
        if (assigns[v] != -1) return assigns[v] == want;
        assigns[v] = want;
        phase[v] = want;
        levels[v] = decision_level();
        reasons[v] = reason;
        trail.push_back(lit);
        return true;
    }

    void attach_clause(int ci) {
        CDCLClause& c = clauses[ci];
        if (c.lits.empty()) return;
        c.watch0 = 0;
        c.watch1 = c.lits.size() == 1 ? 0 : 1;
        watches[lit_index(c.lits[c.watch0])].push_back(ci);
        if (c.watch1 != c.watch0) watches[lit_index(c.lits[c.watch1])].push_back(ci);
    }

    bool initialize_watches() {
        for (int ci = 0; ci < (int)clauses.size(); ++ci) {
            attach_clause(ci);
            if (clauses[ci].lits.size() == 1) {
                if (!enqueue(clauses[ci].lits[0], ci)) return false;
            }
        }
        return true;
    }

    int propagate() {
        while (qhead < (int)trail.size()) {
            int false_lit = -trail[qhead++];
            std::vector<int>& ws = watches[lit_index(false_lit)];
            int i = 0;
            while (i < (int)ws.size()) {
                int ci = ws[i];
                CDCLClause& c = clauses[ci];
                if (c.deleted) {
                    ws[i] = ws.back();
                    ws.pop_back();
                    continue;
                }
                if (c.lits[c.watch0] != false_lit) {
                    std::swap(c.watch0, c.watch1);
                }
                if (c.lits[c.watch0] != false_lit) {
                    ++i;
                    continue;
                }
                int other = c.lits[c.watch1];
                if (lit_value(other) == 1) {
                    ++i;
                    continue;
                }
                bool found = false;
                for (int k = 0; k < (int)c.lits.size(); ++k) {
                    if (k == c.watch0 || k == c.watch1) continue;
                    if (lit_value(c.lits[k]) != 0) {
                        c.watch0 = k;
                        ws[i] = ws.back();
                        ws.pop_back();
                        watches[lit_index(c.lits[k])].push_back(ci);
                        found = true;
                        break;
                    }
                }
                if (found) continue;
                if (lit_value(other) == 0) return ci;
                if (!enqueue(other, ci)) return ci;
                ++i;
            }
        }
        return -1;
    }

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

    void backtrack(int lvl) {
        if (decision_level() <= lvl) return;
        int keep = 0;
        if (lvl == 0) {
            keep = trail_lim.empty() ? (int)trail.size() : trail_lim[0];
        } else {
            keep = trail_lim[lvl];
        }
        for (int i = (int)trail.size() - 1; i >= keep; --i) {
            int v = std::abs(trail[i]);
            assigns[v] = -1;
            reasons[v] = -1;
            levels[v] = 0;
        }
        trail.resize(keep);
        trail_lim.resize(lvl);
        qhead = (int)trail.size();
    }

    void bump_var(int v) {
        activity[v] += var_inc;
        heap.push({activity[v], heap_key(v)});
        if (activity[v] > 1e100) {
            for (int i = 1; i <= nvars; ++i) activity[i] *= 1e-100;
            var_inc *= 1e-100;
            std::priority_queue<std::pair<double, int>> rebuilt;
            for (int i = 1; i <= nvars; ++i) {
                if (decision_allowed[i]) rebuilt.push({activity[i], heap_key(i)});
            }
            heap.swap(rebuilt);
        }
    }

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

    int pick_branch_lit() {
        while (!heap.empty()) {
            auto [act, key] = heap.top();
            heap.pop();
            int v = heap_var(key);
            if (!decision_allowed[v] || assigns[v] != -1) continue;
            if (std::fabs(act - activity[v]) > 1e-12 * std::max(1.0, std::fabs(activity[v]))) continue;
            return phase[v] ? v : -v;
        }
        for (int v = 1; v <= nvars; ++v) {
            if (decision_allowed[v] && assigns[v] == -1) return phase[v] ? v : -v;
        }
        return 0;
    }

    void write_rup_clause(const std::vector<int>& lits) {
        proof << "rup ";
        for (int lit : lits) {
            proof << "1 ";
            if (lit < 0) proof << "~";
            proof << "x" << std::abs(lit) << " ";
        }
        proof << ">= 1 ;\n";
    }

    void write_empty_rup() {
        proof << "rup >= 1 ;\n";
    }

    void finish_unsat_proof() {
        proof << "\noutput NONE ;\n";
        proof << "conclusion UNSAT : -1 ;\n";
        proof << "end pseudo-Boolean proof ;\n";
        proof.flush();
    }

    int compute_lbd(const std::vector<int>& lits) {
        ++level_stamp;
        if (level_stamp == 0x3fffffff) {
            std::fill(level_seen.begin(), level_seen.end(), 0);
            level_stamp = 1;
        }
        int count = 0;
        for (int lit : lits) {
            int lvl = levels[std::abs(lit)];
            if (lvl < 0) lvl = 0;
            if (lvl >= (int)level_seen.size()) lvl = (int)level_seen.size() - 1;
            if (level_seen[lvl] != level_stamp) {
                level_seen[lvl] = level_stamp;
                ++count;
            }
        }
        return count;
    }

    int add_learned_clause(const std::vector<int>& learnt, int lbd) {
        CDCLClause c;
        c.lits = learnt;
        c.learnt = true;
        c.lbd = lbd;
        int ci = (int)clauses.size();
        clauses.push_back(std::move(c));
        attach_clause(ci);
        write_rup_clause(learnt);
        ++learned;
        return ci;
    }

    void reduce_database() {
        backtrack(0);
        int protect_from = std::max(original_clause_count, (int)clauses.size() - protect_recent);
        long long removed = 0;
        for (int ci = original_clause_count; ci < protect_from; ++ci) {
            CDCLClause& c = clauses[ci];
            if (c.deleted || !c.learnt) continue;
            if (c.lits.size() <= 2) continue;
            if (c.lbd <= keep_lbd && c.lits.size() <= (size_t)keep_size) continue;
            c.deleted = true;
            std::vector<int>().swap(c.lits);
            ++removed;
        }
        deleted_clauses += removed;
        if (removed > 0) {
            std::printf("c cdcl reduced removed=%lld total-deleted=%lld active-clauses~=%zu\n",
                        removed, deleted_clauses, clauses.size() - (size_t)deleted_clauses);
            std::fflush(stdout);
        }
    }

    bool learn_root_unit(int lit) {
        std::vector<int> unit{lit};
        int ci = add_learned_clause(unit, 1);
        if (!enqueue(lit, ci)) {
            write_empty_rup();
            finish_unsat_proof();
            return true;
        }
        int confl = propagate();
        if (confl >= 0) {
            write_empty_rup();
            finish_unsat_proof();
            return true;
        }
        return false;
    }

    bool failed_literal_probe() {
        if (probe_limit <= 0) return false;
        int probed = 0, units = 0;
        for (int v = 1; v <= nvars && probed < probe_limit; ++v) {
            if (!decision_allowed[v] || assigns[v] != -1) continue;
            for (int sign = 0; sign < 2; ++sign) {
                int lit = sign ? v : -v;
                if (assigns[v] != -1) break;
                new_decision_level();
                enqueue(lit, -1);
                int confl = propagate();
                backtrack(0);
                if (confl >= 0) {
                    if (learn_root_unit(-lit)) return true;
                    ++units;
                    break;
                }
            }
            ++probed;
        }
        if (probed || units) {
            std::printf("c cdcl failed-literal probed=%d units=%d trail=%zu\n", probed, units, trail.size());
            std::fflush(stdout);
        }
        return false;
    }

    int analyze(int confl, std::vector<int>& learnt) {
        learnt.clear();
        learnt.push_back(0);
        int path_count = 0;
        int p = 0;
        int idx = (int)trail.size() - 1;
        int current = decision_level();
        std::vector<int> touched;

        do {
            const CDCLClause& c = clauses[confl];
            for (int lit : c.lits) {
                int v = std::abs(lit);
                if (v == std::abs(p)) continue;
                if (!seen[v] && levels[v] > 0) {
                    seen[v] = 1;
                    touched.push_back(v);
                    bump_var(v);
                    if (levels[v] == current) {
                        ++path_count;
                    } else {
                        learnt.push_back(lit);
                    }
                }
            }
            do {
                p = trail[idx--];
            } while (!seen[std::abs(p)]);
            seen[std::abs(p)] = 0;
            --path_count;
            confl = reasons[std::abs(p)];
        } while (path_count > 0);

        learnt[0] = -p;
        int backtrack_level = 0;
        for (int i = 1; i < (int)learnt.size(); ++i) {
            backtrack_level = std::max(backtrack_level, levels[std::abs(learnt[i])]);
        }
        for (int v : touched) seen[v] = 0;
        decay_activity();
        return backtrack_level;
    }

    void minimize_learnt(std::vector<int>& learnt) {
        if (learnt.size() <= 2) return;
        std::vector<int> marked;
        marked.reserve(learnt.size());
        for (int lit : learnt) {
            int v = std::abs(lit);
            if (!seen[v]) {
                seen[v] = 1;
                marked.push_back(v);
            }
        }

        std::vector<int> out;
        out.reserve(learnt.size());
        out.push_back(learnt[0]);
        for (int i = 1; i < (int)learnt.size(); ++i) {
            int lit = learnt[i];
            int v = std::abs(lit);
            int rc = reasons[v];
            bool removable = rc >= 0 && !clauses[rc].deleted;
            if (removable) {
                const CDCLClause& reason_clause = clauses[rc];
                for (int q : reason_clause.lits) {
                    int qv = std::abs(q);
                    if (qv == v || levels[qv] == 0) continue;
                    if (!seen[qv]) {
                        removable = false;
                        break;
                    }
                }
            }
            if (!removable) out.push_back(lit);
        }
        for (int v : marked) seen[v] = 0;
        learnt.swap(out);
    }

    bool solve(const char* proof_path, double seconds) {
        proof.open(proof_path);
        if (!proof) return false;
        proof << "pseudo-Boolean proof version 3.0\n\n";
        deadline = Clock::now() + std::chrono::milliseconds((int)(seconds * 1000));

        if (!initialize_watches()) {
            write_empty_rup();
            finish_unsat_proof();
            return true;
        }
        int confl = propagate();
        if (confl >= 0) {
            write_empty_rup();
            finish_unsat_proof();
            return true;
        }
        if (failed_literal_probe()) return true;

        std::vector<int> learnt;
        long long restart_limit = 512;
        long long next_restart = restart_limit;
        long long next_reduce = reduce_interval;
        while (Clock::now() < deadline) {
            confl = propagate();
            if (confl >= 0) {
                ++conflicts;
                if (decision_level() == 0) {
                    write_empty_rup();
                    finish_unsat_proof();
                    return true;
                }
                int back = analyze(confl, learnt);
                minimize_learnt(learnt);
                back = 0;
                for (int i = 1; i < (int)learnt.size(); ++i) {
                    back = std::max(back, levels[std::abs(learnt[i])]);
                }
                int lbd = compute_lbd(learnt);
                backtrack(back);
                int ci = add_learned_clause(learnt, lbd);
                if (!enqueue(learnt[0], ci)) {
                    write_empty_rup();
                    finish_unsat_proof();
                    return true;
                }
                if (use_restarts && conflicts >= next_restart) {
                    backtrack(0);
                    restart_limit = restart_limit + restart_limit / 2 + 64;
                    next_restart = conflicts + restart_limit;
                }
                if (conflicts >= next_reduce) {
                    reduce_database();
                    next_reduce = conflicts + reduce_interval;
                }
                if ((conflicts & 8191) == 0) {
                    std::printf("c cdcl conflicts=%lld learned=%lld deleted=%lld level=%d trail=%zu clauses=%zu\n",
                                conflicts, learned, deleted_clauses, decision_level(), trail.size(), clauses.size());
                    std::fflush(stdout);
                }
            } else {
                int lit = pick_branch_lit();
                if (lit == 0) return false;
                new_decision_level();
                enqueue(lit, -1);
            }
        }
        proof.flush();
        return false;
    }

    void detect_primary_decisions(const Solver& s) {
        if (const char* e = std::getenv("CDCL_ALL_DECISIONS")) {
            if (std::atoi(e) != 0) {
                std::fill(decision_allowed.begin(), decision_allowed.end(), 1);
                if (!decision_allowed.empty()) decision_allowed[0] = 0;
                return;
            }
        }
        std::vector<uint8_t> output(nvars + 1, 0);
        auto bin_key = [](int a, int b) -> uint64_t {
            if (a > b) std::swap(a, b);
            return ((uint64_t)(uint32_t)a << 32) ^ (uint32_t)b;
        };
        std::unordered_set<uint64_t> binaries;
        binaries.reserve((size_t)s.nclauses * 2);
        for (int ci = 0; ci < (int)s.clauses.size(); ++ci) {
            const Clause& c = s.clauses[ci];
            if (c.len != 2) continue;
            int a = s.lits[c.off], b = s.lits[c.off + 1];
            binaries.insert(bin_key(a, b));
        }

        for (int ci = 0; ci < (int)s.clauses.size(); ++ci) {
            const Clause& c = s.clauses[ci];
            if (c.len != 3) continue;
            int lits3[3] = {s.lits[c.off], s.lits[c.off + 1], s.lits[c.off + 2]};
            int pos = 0, negs[2], nneg = 0, npos = 0;
            for (int lit : lits3) {
                if (lit > 0) {
                    pos = lit;
                    ++npos;
                } else if (nneg < 2) {
                    negs[nneg++] = -lit;
                }
            }
            if (npos == 1 && nneg == 2) {
                if (binaries.count(bin_key(-pos, negs[0])) &&
                    binaries.count(bin_key(-pos, negs[1]))) {
                    output[pos] = 1;
                }
            }
        }

        for (int ci = 0; ci < (int)s.clauses.size(); ++ci) {
            const Clause& c = s.clauses[ci];
            if (c.len == 4) output[std::abs(s.lits[c.off])] = 1;
        }

        int primaries = 0;
        for (int v = 1; v <= nvars; ++v) {
            decision_allowed[v] = output[v] ? 0 : 1;
            primaries += decision_allowed[v] ? 1 : 0;
        }
        int rank = s.brent_rank_guess();
        if (rank <= 0 || primaries != 27 * rank) {
            std::fill(decision_allowed.begin(), decision_allowed.end(), 1);
            if (!decision_allowed.empty()) decision_allowed[0] = 0;
        }
    }
};

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Solver s;
    if (!s.parse(argv[1])) {
        std::printf("s UNKNOWN\n");
        return 0;
    }
    double limit = 590.0;
    if (const char* e = std::getenv("SOLVER_SECONDS")) limit = std::atof(e);
    std::printf("c brent structural local-search solver vars=%d clauses=%d fixed-units=%zu limit=%.1f\n",
                s.nvars, s.nclauses,
                (size_t)std::count_if(s.fixed.begin(), s.fixed.end(), [](int8_t x) { return x != -1; }),
                limit);
    std::fflush(stdout);
    int rank = s.brent_rank_guess();
    if (rank > 0 && rank < 19) {
        const char* cdcl_env = std::getenv("SOLVER_ENABLE_CDCL_UNSAT");
        if (rank == 9 && cdcl_env && std::atoi(cdcl_env) != 0) {
            std::printf("c detected brent rank=9; trying proof-producing CDCL refutation\n");
            std::fflush(stdout);
            ProofCDCL cdcl(s);
            if (cdcl.solve(argv[2], std::max(1.0, limit - 2.0))) {
                std::printf("c cdcl proved UNSAT conflicts=%lld learned=%lld\n", cdcl.conflicts, cdcl.learned);
                std::printf("s UNSATISFIABLE\n");
                return 20;
            }
            std::printf("c cdcl did not finish within limit; returning UNKNOWN\n");
            std::printf("s UNKNOWN\n");
            return 0;
        }
        std::printf("c detected brent rank=%d below supported constructive/local-search range; returning UNKNOWN\n", rank);
        std::printf("s UNKNOWN\n");
        return 0;
    }
    if (s.search(limit)) {
        s.print_model();
        return 10;
    }
    std::printf("s UNKNOWN\n");
    return 0;
}
