#include <algorithm>
#include <chrono>
#include <atomic>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <mutex>
#include <numeric>
#include <random>
#include <sstream>
#include <string>
#include <thread>
#include <vector>

using namespace std;

struct Clause { vector<int> v; };
struct Solver {
    int n = 0;
    vector<Clause> pos, neg;
    vector<vector<int>> posOcc, negOcc;
    vector<unsigned char> sel, ban;
    vector<unsigned short> hit;
    int uncovered = 0;
    chrono::steady_clock::time_point deadline;
    mt19937 rng{1};
    long long nodes = 0;
    vector<int> ls_model;
    ofstream proof;
    vector<int> decisions;
    long long proof_lines = 0;
    long long proof_line_limit = 4000000;

    struct TrailRec { int type, id; }; // 0 sel, 1 ban, 2 hit
    vector<TrailRec> trail;

    bool timed_out() const { return chrono::steady_clock::now() >= deadline; }

    bool read_dimacs(const string& path) {
        ifstream in(path);
        if (!in) return false;
        string tok;
        int declared_m = 0;
        while (in >> tok) {
            if (tok == "c") { string rest; getline(in, rest); continue; }
            if (tok == "p") { string cnf; in >> cnf >> n >> declared_m; continue; }
            int lit = stoi(tok);
            vector<int> lits;
            if (lit != 0) lits.push_back(lit);
            while (in >> lit && lit != 0) lits.push_back(lit);
            if (lits.empty()) return false;
            bool allp = true, alln = true;
            vector<int> vars;
            for (int x : lits) {
                allp &= x > 0; alln &= x < 0;
                vars.push_back(abs(x));
            }
            sort(vars.begin(), vars.end());
            vars.erase(unique(vars.begin(), vars.end()), vars.end());
            if (allp) pos.push_back({vars});
            else if (alln) neg.push_back({vars});
            else return false;
        }
        if (n <= 0 || neg.empty() || pos.empty()) return false;
        posOcc.assign(n + 1, {}); negOcc.assign(n + 1, {});
        for (int i = 0; i < (int)pos.size(); ++i) for (int v : pos[i].v) if (v>=1 && v<=n) posOcc[v].push_back(i); else return false;
        for (int i = 0; i < (int)neg.size(); ++i) for (int v : neg[i].v) if (v>=1 && v<=n) negOcc[v].push_back(i); else return false;
        sel.assign(n + 1, 0); ban.assign(n + 1, 0); hit.assign(neg.size(), 0); uncovered = (int)neg.size();
        return true;
    }

    bool add_ban(int v) {
        if (sel[v]) return false;
        if (!ban[v]) { ban[v] = 1; trail.push_back({1, v}); }
        return true;
    }

    bool add_sel(int v) {
        if (sel[v]) return true;
        if (ban[v]) return false;
        sel[v] = 1; trail.push_back({0, v});
        for (int ci : negOcc[v]) {
            if (hit[ci] == 0) --uncovered;
            ++hit[ci]; trail.push_back({2, ci});
        }
        for (int ci : posOcc[v]) {
            const auto& c = pos[ci].v;
            int cnt = 0, last = -1;
            for (int u : c) {
                if (sel[u]) ++cnt;
                else last = u;
            }
            if (cnt == (int)c.size()) return false;
            if (cnt == (int)c.size() - 1 && last != -1) {
                if (!add_ban(last)) return false;
            }
        }
        return true;
    }

    void undo(size_t mark) {
        while (trail.size() > mark) {
            auto r = trail.back(); trail.pop_back();
            if (r.type == 0) sel[r.id] = 0;
            else if (r.type == 1) ban[r.id] = 0;
            else {
                --hit[r.id];
                if (hit[r.id] == 0) ++uncovered;
            }
        }
    }

    bool propagate() {
        bool changed = true;
        while (changed) {
            if (timed_out()) return false;
            changed = false;
            for (int ci = 0; ci < (int)neg.size(); ++ci) if (hit[ci] == 0) {
                int cnt = 0, last = -1;
                for (int v : neg[ci].v) if (!sel[v] && !ban[v]) { ++cnt; last = v; if (cnt > 1) break; }
                if (cnt == 0) return false;
                if (cnt == 1) {
                    size_t before = trail.size();
                    if (!add_sel(last)) return false;
                    if (trail.size() != before) changed = true;
                }
            }
        }
        return true;
    }

    int propagate_exact() {
        bool changed = true;
        while (changed) {
            if (timed_out()) return -1;
            changed = false;
            for (int ci = 0; ci < (int)neg.size(); ++ci) if (hit[ci] == 0) {
                int cnt = 0, last = -1;
                for (int v : neg[ci].v) if (!sel[v] && !ban[v]) { ++cnt; last = v; if (cnt > 1) break; }
                if (cnt == 0) return 0;
                if (cnt == 1) {
                    size_t before = trail.size();
                    if (!add_sel(last)) return 0;
                    if (trail.size() != before) changed = true;
                }
            }
        }
        return 1;
    }

    bool write_blocking_rup() {
        if (!proof || proof_lines >= proof_line_limit) return false;
        proof << "rup";
        for (int v : decisions) proof << " 1 x" << v;
        proof << " >= 1 ;\n";
        ++proof_lines;
        return (bool)proof;
    }

    int choose_clause(vector<int>& candidates) {
        int best = -1, bestcnt = 1e9;
        candidates.clear();
        for (int ci = 0; ci < (int)neg.size(); ++ci) if (hit[ci] == 0) {
            int cnt = 0;
            for (int v : neg[ci].v) if (!sel[v] && !ban[v]) ++cnt;
            if (cnt == 0) return -2;
            if (cnt < bestcnt) { bestcnt = cnt; best = ci; if (cnt == 1) break; }
        }
        if (best < 0) return -1;
        candidates.reserve(neg[best].v.size());
        for (int v : neg[best].v) if (!sel[v] && !ban[v]) candidates.push_back(v);
        return best;
    }

    int gain(int v) const {
        int g = 0;
        for (int ci : negOcc[v]) if (hit[ci] == 0) ++g;
        return g;
    }

    void reset_search_state() {
        fill(sel.begin(), sel.end(), 0);
        fill(ban.begin(), ban.end(), 0);
        fill(hit.begin(), hit.end(), 0);
        uncovered = (int)neg.size();
        trail.clear();
    }

    int added_ban_pressure(int v) const {
        int pressure = 0;
        for (int ci : posOcc[v]) {
            const auto& c = pos[ci].v;
            int selected = 0;
            int open = 0;
            for (int u : c) {
                if (u == v) continue;
                if (sel[u]) ++selected;
                else if (!ban[u]) ++open;
            }
            if (selected == (int)c.size() - 1) return 1000000000;
            if (selected == (int)c.size() - 2 && open > 0) pressure += open;
        }
        return pressure;
    }

    bool greedy_construct(double seconds) {
        if (seconds <= 0.0) return false;
        auto end = chrono::steady_clock::now() + chrono::milliseconds((int)(seconds * 1000));
        vector<int> cand;
        uniform_real_distribution<double> prob(0.0, 1.0);
        const double penalties[] = {0.00, 0.06, 0.12, 0.20, 0.35};
        int restart = 0;
        while (chrono::steady_clock::now() < end && !timed_out()) {
            reset_search_state();
            rng.seed(0x9e3779b9u * (uint32_t)(++restart) + (uint32_t)n * 911u + (uint32_t)neg.size());
            double penalty = penalties[restart % 5];
            bool dead = false;
            while (uncovered > 0 && chrono::steady_clock::now() < end && !timed_out()) {
                if (!propagate()) { dead = true; break; }
                if (uncovered == 0) return true;

                int bestcnt = 1000000000;
                vector<int> best_clauses;
                for (int ci = 0; ci < (int)neg.size(); ++ci) if (hit[ci] == 0) {
                    int cnt = 0;
                    for (int v : neg[ci].v) if (!sel[v] && !ban[v]) ++cnt;
                    if (cnt == 0) { dead = true; break; }
                    if (cnt < bestcnt) {
                        bestcnt = cnt;
                        best_clauses.clear();
                        best_clauses.push_back(ci);
                    } else if (cnt == bestcnt && (int)best_clauses.size() < 64) {
                        best_clauses.push_back(ci);
                    }
                }
                if (dead || best_clauses.empty()) break;
                int ci = best_clauses[rng() % best_clauses.size()];

                cand.clear();
                for (int v : neg[ci].v) if (!sel[v] && !ban[v]) cand.push_back(v);
                if (cand.empty()) { dead = true; break; }

                int chosen = cand[0];
                double bestscore = -1e100;
                for (int v : cand) {
                    int pressure = added_ban_pressure(v);
                    if (pressure >= 1000000000) continue;
                    double score = (double)gain(v) - penalty * (double)pressure + prob(rng) * (2.5 + 0.05 * bestcnt);
                    if (score > bestscore) {
                        bestscore = score;
                        chosen = v;
                    }
                }
                if (bestscore < -1e90) { dead = true; break; }
                if (!add_sel(chosen)) { dead = true; break; }
            }
            if (!dead && uncovered == 0) return true;
        }
        return false;
    }

    bool dfs(int depth) {
        if (++nodes % 2048 == 0 && timed_out()) return false;
        size_t mark = trail.size();
        if (!propagate()) { undo(mark); return false; }
        if (uncovered == 0) return true;
        vector<int> cand;
        int ci = choose_clause(cand);
        if (ci < 0) { undo(mark); return ci == -1; }
        shuffle(cand.begin(), cand.end(), rng);
        sort(cand.begin(), cand.end(), [&](int a, int b){ return gain(a) > gain(b); });
        for (int v : cand) {
            if (timed_out()) break;
            size_t m2 = trail.size();
            if (add_sel(v) && dfs(depth + 1)) return true;
            undo(m2);
        }
        undo(mark);
        return false;
    }

    enum class ExactResult { Sat, Unsat, Abort };

    ExactResult dfs_proof() {
        if (++nodes % 2048 == 0 && timed_out()) return ExactResult::Abort;
        if (proof_lines >= proof_line_limit) return ExactResult::Abort;
        size_t mark = trail.size();
        int pr = propagate_exact();
        if (pr < 0) { undo(mark); return ExactResult::Abort; }
        if (pr == 0) {
            bool ok = write_blocking_rup();
            undo(mark);
            return ok ? ExactResult::Unsat : ExactResult::Abort;
        }
        if (uncovered == 0) return ExactResult::Sat;

        vector<int> cand;
        int ci = choose_clause(cand);
        if (ci < 0) {
            if (ci == -1) return ExactResult::Sat;
            bool ok = write_blocking_rup();
            undo(mark);
            return ok ? ExactResult::Unsat : ExactResult::Abort;
        }

        shuffle(cand.begin(), cand.end(), rng);
        sort(cand.begin(), cand.end(), [&](int a, int b){ return gain(a) > gain(b); });
        for (int v : cand) {
            if (timed_out()) { undo(mark); return ExactResult::Abort; }
            size_t m2 = trail.size();
            decisions.push_back(v);
            ExactResult r;
            if (add_sel(v)) r = dfs_proof();
            else {
                bool ok = write_blocking_rup();
                r = ok ? ExactResult::Unsat : ExactResult::Abort;
            }
            decisions.pop_back();
            if (r == ExactResult::Sat) return ExactResult::Sat;
            undo(m2);
            if (r == ExactResult::Abort) { undo(mark); return ExactResult::Abort; }
        }

        bool ok = write_blocking_rup();
        undo(mark);
        return ok ? ExactResult::Unsat : ExactResult::Abort;
    }

    bool verify_model(const vector<int>& assignment) const {
        for (const auto& c : pos) {
            bool sat = false;
            for (int v : c.v) if (assignment[v] > 0) { sat = true; break; }
            if (!sat) return false;
        }
        for (const auto& c : neg) {
            bool sat = false;
            for (int v : c.v) if (assignment[v] < 0) { sat = true; break; }
            if (!sat) return false;
        }
        return true;
    }

    bool local_search(double seconds) {
        struct Occ { int c; bool sign; };
        vector<vector<int>> clauses;
        vector<vector<Occ>> occ(n + 1);
        clauses.reserve(pos.size() + neg.size());
        for (const auto& c : pos) {
            int id = clauses.size(); clauses.push_back(c.v);
            for (int v : c.v) occ[v].push_back({id, true});
        }
        for (const auto& c : neg) {
            int id = clauses.size(); clauses.push_back(c.v);
            for (int v : c.v) occ[v].push_back({id, false});
        }
        bool use_weights = getenv("CLAUSE_WEIGHTS") != nullptr;
        auto end = chrono::steady_clock::now() + chrono::milliseconds((int)(seconds * 1000));
        const double pmin[] = {0.055, 0.075, 0.095, 0.115, 0.070, 0.090, 0.050, 0.125};
        const double pspan[] = {0.075, 0.095, 0.110, 0.130, 0.150, 0.180, 0.200, 0.220};
        const double noise[] = {0.035, 0.060, 0.090, 0.120, 0.180, 0.240, 0.300, 0.420};
        int only_regime = getenv("LS_REGIME") ? atoi(getenv("LS_REGIME")) : -1;
        int thread_count = getenv("LS_THREADS") ? max(1, atoi(getenv("LS_THREADS"))) : (n >= 200 ? 2 : 1);
        thread_count = min(thread_count, 4);
        atomic<bool> found(false);
        mutex found_mutex;
        vector<int> found_model;

        auto worker = [&](int worker_id) {
            vector<unsigned short> satcnt(clauses.size());
            vector<unsigned short> weight(clauses.size(), 1);
            vector<int> makecnt(n + 1), breakcnt(n + 1);
            vector<int> unsat, where(clauses.size(), -1);
            vector<unsigned char> val(n + 1, 1);
            vector<int> ties;
            mt19937 local_rng(1);
            uniform_real_distribution<double> prob(0.0, 1.0);
            auto add_unsat = [&](int c){ if (where[c] < 0) { where[c] = (int)unsat.size(); unsat.push_back(c); } };
            auto rem_unsat = [&](int c){ int p = where[c]; if (p >= 0) { int last = unsat.back(); unsat[p] = last; where[last] = p; unsat.pop_back(); where[c] = -1; } };
            auto lit_true = [&](int v, bool sign){ return (bool)val[v] == sign; };

            for (int seed = 1 + worker_id; !found.load(memory_order_relaxed) && chrono::steady_clock::now() < end; seed += thread_count) {
                local_rng.seed((uint32_t)seed * 2654435761u + (uint32_t)n * 17u + (uint32_t)pos.size());
                int regime = only_regime >= 0 ? (only_regime & 7) : (seed & 7);
                double span = pspan[regime], walk_noise = noise[regime];
                if (n < 270 && regime == 1) { span = 0.115; walk_noise = 0.120; }
                double false_p = pmin[regime] + span * prob(local_rng);
                for (int v = 1; v <= n; ++v) val[v] = prob(local_rng) >= false_p;
                fill(satcnt.begin(), satcnt.end(), 0); fill(where.begin(), where.end(), -1); unsat.clear();
                fill(weight.begin(), weight.end(), 1);
                fill(makecnt.begin(), makecnt.end(), 0);
                fill(breakcnt.begin(), breakcnt.end(), 0);
                for (int ci = 0; ci < (int)clauses.size(); ++ci) {
                    int cnt = 0; bool sign = ci < (int)pos.size();
                    for (int v : clauses[ci]) if (lit_true(v, sign)) ++cnt;
                    satcnt[ci] = cnt;
                    if (cnt == 0) {
                        add_unsat(ci);
                        for (int v : clauses[ci]) ++makecnt[v];
                    } else if (cnt == 1) {
                        for (int v : clauses[ci]) if (lit_true(v, sign)) { ++breakcnt[v]; break; }
                    }
                }
                auto find_true_except = [&](int cid, int except) {
                    bool sign = cid < (int)pos.size();
                    for (int u : clauses[cid]) if (u != except && lit_true(u, sign)) return u;
                    return 0;
                };
                auto flip_var = [&](int chosen) {
                    bool old = val[chosen]; val[chosen] = !old;
                    for (auto o : occ[chosen]) {
                        bool was = old == o.sign;
                        int w = use_weights ? weight[o.c] : 1;
                        int before = satcnt[o.c];
                        if (was) {
                            if (before == 1) {
                                breakcnt[chosen] -= w;
                                add_unsat(o.c);
                                for (int u : clauses[o.c]) makecnt[u] += w;
                            } else if (before == 2) {
                                int other = find_true_except(o.c, chosen);
                                if (other > 0) breakcnt[other] += w;
                            }
                            --satcnt[o.c];
                        } else {
                            if (before == 0) {
                                rem_unsat(o.c);
                                for (int u : clauses[o.c]) makecnt[u] -= w;
                                breakcnt[chosen] += w;
                            } else if (before == 1) {
                                int other = find_true_except(o.c, chosen);
                                if (other > 0) breakcnt[other] -= w;
                            }
                            ++satcnt[o.c];
                        }
                    }
                };

                int max_flips = (n >= 270 ? 20000000 : 3000000);
                for (int flip = 0; flip < max_flips && !found.load(memory_order_relaxed) && chrono::steady_clock::now() < end; ++flip) {
                    if (unsat.empty()) {
                        vector<int> candidate(n + 1, 0);
                        for (int v = 1; v <= n; ++v) candidate[v] = val[v] ? v : -v;
                        if (verify_model(candidate)) {
                            lock_guard<mutex> lock(found_mutex);
                            if (!found.load(memory_order_relaxed)) {
                                found_model = std::move(candidate);
                                found.store(true, memory_order_relaxed);
                            }
                        }
                        break;
                    }
                    int ci = unsat[local_rng() % unsat.size()];
                    if (use_weights && weight[ci] < 4096) {
                        ++weight[ci];
                        for (int v : clauses[ci]) ++makecnt[v];
                    }
                    const auto& c = clauses[ci];
                    int chosen = 0;
                    if (prob(local_rng) < walk_noise) chosen = c[local_rng() % c.size()];
                    else {
                        int best = 1000000000;
                        ties.clear();
                        ties.reserve(c.size());
                        for (int v : c) {
                            int score = breakcnt[v] - makecnt[v];
                            if (score < best) { best = score; ties.clear(); ties.push_back(v); }
                            else if (score == best) ties.push_back(v);
                        }
                        chosen = ties[local_rng() % ties.size()];
                    }
                    flip_var(chosen);
                    if ((flip & 262143) == 0 && timed_out()) break;
                }
            }
        };

        if (thread_count == 1) worker(0);
        else {
            vector<thread> threads;
            threads.reserve(thread_count);
            for (int i = 0; i < thread_count; ++i) threads.emplace_back(worker, i);
            for (auto& t : threads) t.join();
        }
        if (!found.load(memory_order_relaxed)) return false;
        ls_model = found_model;
        fill(sel.begin(), sel.end(), 0);
        for (int v = 1; v <= n; ++v) if (ls_model[v] < 0) sel[v] = 1;
        return true;
    }

    bool solve(double seconds) {
        deadline = chrono::steady_clock::now() + chrono::milliseconds((int)(seconds * 1000));
        double greedy_seconds = getenv("GREEDY_SECONDS") ? atof(getenv("GREEDY_SECONDS")) : 0.0;
        if (greedy_construct(greedy_seconds)) return true;
        double ls_seconds = getenv("SKIP_LOCAL") ? 0.0 : min(580.0, seconds * 0.99);
        if (local_search(ls_seconds)) return true;
        if (!getenv("USE_DFS")) return false;
        // Try several deterministic randomized branch orders inside one process.
        for (int seed = 1; seed <= 80 && !timed_out(); ++seed) {
            fill(sel.begin(), sel.end(), 0); fill(ban.begin(), ban.end(), 0); fill(hit.begin(), hit.end(), 0);
            uncovered = (int)neg.size(); trail.clear(); nodes = 0; rng.seed(seed * 1000003u + n);
            if (dfs(0)) return true;
        }
        return false;
    }

    ExactResult exact_with_proof(double seconds, const string& proof_path) {
        deadline = chrono::steady_clock::now() + chrono::milliseconds((int)(seconds * 1000));
        fill(sel.begin(), sel.end(), 0);
        fill(ban.begin(), ban.end(), 0);
        fill(hit.begin(), hit.end(), 0);
        uncovered = (int)neg.size();
        trail.clear();
        decisions.clear();
        nodes = 0;
        proof_lines = 0;
        rng.seed((uint32_t)n * 1000003u + (uint32_t)pos.size());

        proof.open(proof_path);
        if (!proof) return ExactResult::Abort;
        proof << "pseudo-Boolean proof version 3.0\n";
        ExactResult r = dfs_proof();
        if (r == ExactResult::Unsat) {
            proof << "output NONE ;\n";
            proof << "conclusion UNSAT : -1 ;\n";
            proof << "end pseudo-Boolean proof ;\n";
        }
        proof.close();
        return r;
    }
};

struct CdclSolver {
    struct CClause {
        vector<int> lits;
        bool learnt = false;
    };

    int n = 0;
    vector<CClause> clauses;
    vector<vector<int>> neg_vars;
    vector<vector<int>> watches;
    vector<signed char> assigns, phase;
    vector<int> levels, reasons, trail, trail_lim;
    vector<double> activity;
    int qhead = 0;
    double var_inc = 1.0;
    double var_decay = 0.95;
    long long conflicts = 0;
    long long proof_lines = 0;
    long long proof_line_limit = 1200000;
    chrono::steady_clock::time_point deadline;
    ofstream proof;

    explicit CdclSolver(const Solver& s) : n(s.n) {
        watches.assign(2 * n + 2, {});
        assigns.assign(n + 1, 0);
        phase.assign(n + 1, -1);
        levels.assign(n + 1, 0);
        reasons.assign(n + 1, -1);
        activity.assign(n + 1, 0.0);
        clauses.reserve(s.pos.size() + s.neg.size() + 100000);
        for (const auto& c : s.pos) {
            vector<int> lits;
            lits.reserve(c.v.size());
            for (int v : c.v) { lits.push_back(v); activity[v] += 1.0; }
            add_clause(lits, false);
        }
        for (const auto& c : s.neg) {
            vector<int> lits;
            lits.reserve(c.v.size());
            neg_vars.push_back(c.v);
            for (int v : c.v) { lits.push_back(-v); activity[v] += 0.25; }
            add_clause(lits, false);
        }
    }

    int lit_index(int lit) const {
        int v = abs(lit);
        return 2 * (v - 1) + (lit < 0);
    }

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

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

    bool timed_out() const { return chrono::steady_clock::now() >= deadline; }

    int add_clause(vector<int> lits, bool learnt) {
        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;
        });
        vector<int> clean;
        clean.reserve(lits.size());
        int prev = 0;
        for (int lit : lits) {
            if (lit == prev) continue;
            if (prev != 0 && abs(prev) == abs(lit) && prev == -lit) return -2;
            clean.push_back(lit);
            prev = lit;
        }
        int id = (int)clauses.size();
        clauses.push_back({std::move(clean), learnt});
        auto& c = clauses.back().lits;
        if (c.size() >= 2) {
            watches[lit_index(c[0])].push_back(id);
            watches[lit_index(c[1])].push_back(id);
        }
        return id;
    }

    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;
        phase[v] = val;
        levels[v] = decision_level();
        reasons[v] = reason;
        trail.push_back(lit);
        return true;
    }

    int propagate() {
        while (qhead < (int)trail.size()) {
            int p = trail[qhead++];
            auto& ws = watches[lit_index(-p)];
            int kept = 0;
            for (int i = 0; i < (int)ws.size(); ++i) {
                int ci = ws[i];
                auto& c = clauses[ci].lits;
                if (c.size() < 2) { ws[kept++] = ci; continue; }
                if (c[0] == -p) swap(c[0], c[1]);
                if (c[1] != -p) { ws[kept++] = ci; continue; }

                int first = c[0];
                if (lit_value(first) == 1) {
                    ws[kept++] = ci;
                    continue;
                }

                bool moved = false;
                for (int k = 2; k < (int)c.size(); ++k) {
                    if (lit_value(c[k]) != -1) {
                        c[1] = c[k];
                        c[k] = -p;
                        watches[lit_index(c[1])].push_back(ci);
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;

                ws[kept++] = ci;
                if (lit_value(first) == -1) {
                    for (++i; i < (int)ws.size(); ++i) ws[kept++] = ws[i];
                    ws.resize(kept);
                    return ci;
                }
                if (!enqueue(first, ci)) {
                    for (++i; i < (int)ws.size(); ++i) ws[kept++] = ws[i];
                    ws.resize(kept);
                    return ci;
                }
            }
            ws.resize(kept);
        }
        return -1;
    }

    void cancel_until(int lvl) {
        if (decision_level() <= lvl) return;
        int lim = trail_lim[lvl];
        for (int i = (int)trail.size() - 1; i >= lim; --i) {
            int v = abs(trail[i]);
            assigns[v] = 0;
            levels[v] = 0;
            reasons[v] = -1;
        }
        trail.resize(lim);
        qhead = lim;
        trail_lim.resize(lvl);
    }

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

    void analyze(int confl, vector<int>& learnt, int& backtrack) {
        vector<unsigned char> seen(n + 1, 0);
        learnt.clear();
        learnt.push_back(0);
        int path_count = 0;
        int p = 0;
        int idx = (int)trail.size() - 1;
        int ci = confl;

        do {
            const auto& c = clauses[ci].lits;
            for (int lit : c) {
                int v = abs(lit);
                if (v == abs(p) || seen[v] || levels[v] == 0) continue;
                seen[v] = 1;
                bump_var(v);
                if (levels[v] == decision_level()) ++path_count;
                else learnt.push_back(lit);
            }
            while (idx >= 0 && !seen[abs(trail[idx])]) --idx;
            if (idx < 0) break;
            p = trail[idx--];
            ci = reasons[abs(p)];
            seen[abs(p)] = 0;
            --path_count;
        } while (path_count > 0 && ci >= 0);

        learnt[0] = -p;
        backtrack = 0;
        for (int i = 1; i < (int)learnt.size(); ++i) backtrack = max(backtrack, levels[abs(learnt[i])]);
    }

    bool write_rup_clause(const vector<int>& lits) {
        if (!proof || proof_lines >= proof_line_limit) return false;
        proof << "rup";
        for (int lit : lits) {
            if (lit > 0) proof << " 1 x" << lit;
            else proof << " 1 ~x" << -lit;
        }
        proof << " >= 1 ;\n";
        ++proof_lines;
        return (bool)proof;
    }

    int current_unhit_gain(int var) const {
        int g = 0;
        for (const auto& c : neg_vars) {
            bool hit = false;
            bool contains = false;
            for (int v : c) {
                if (assigns[v] == -1) { hit = true; break; }
                if (v == var) contains = true;
            }
            if (!hit && contains) ++g;
        }
        return g;
    }

    int pick_branch_lit() const {
        bool use_gain_branch = getenv("CDCL_GAIN_BRANCH") != nullptr;
        int best_clause_count = 1000000000;
        int best_var = 0;
        double best_var_act = -1.0;
        for (const auto& c : neg_vars) {
            bool hit = false;
            int open = 0;
            int clause_best = 0;
            double clause_best_act = -1.0;
            for (int v : c) {
                if (assigns[v] == -1) { hit = true; break; }
                if (assigns[v] == 0) {
                    ++open;
                    double score = use_gain_branch ? (double)current_unhit_gain(v) * 1000000.0 + activity[v] : activity[v];
                    if (score > clause_best_act) {
                        clause_best_act = score;
                        clause_best = v;
                    }
                }
            }
            if (!hit && open > 0) {
                if (open < best_clause_count ||
                    (open == best_clause_count && clause_best_act > best_var_act)) {
                    best_clause_count = open;
                    best_var = clause_best;
                    best_var_act = clause_best_act;
                }
            }
        }
        if (best_var == 0) return 0;
        return -best_var;
    }

    enum class Result { Sat, Unsat, Unknown };

    Result solve(double seconds, const string& proof_path, vector<int>& model) {
        deadline = chrono::steady_clock::now() + chrono::milliseconds((int)(seconds * 1000));
        proof.open(proof_path);
        if (!proof) return Result::Unknown;
        proof << "pseudo-Boolean proof version 3.0\n";

        int confl = propagate();
        if (confl >= 0) {
            vector<int> empty;
            if (!write_rup_clause(empty)) return Result::Unknown;
            proof << "output NONE ;\nconclusion UNSAT : -1 ;\nend pseudo-Boolean proof ;\n";
            proof.close();
            return Result::Unsat;
        }

        int restart_limit = 128;
        int conflicts_since_restart = 0;
        vector<int> learnt;
        while (!timed_out() && proof_lines < proof_line_limit) {
            confl = propagate();
            if (confl >= 0) {
                ++conflicts;
                ++conflicts_since_restart;
                if (decision_level() == 0) {
                    vector<int> empty;
                    if (!write_rup_clause(empty)) break;
                    proof << "output NONE ;\nconclusion UNSAT : -1 ;\nend pseudo-Boolean proof ;\n";
                    proof.close();
                    return Result::Unsat;
                }

                int backtrack = 0;
                analyze(confl, learnt, backtrack);
                if (learnt.empty() || learnt[0] == 0) break;
                if (!write_rup_clause(learnt)) break;
                cancel_until(backtrack);
                int cid = add_clause(learnt, true);
                if (cid == -2) continue;
                if (!enqueue(learnt[0], cid)) break;
                var_inc /= var_decay;

                if (conflicts_since_restart >= restart_limit) {
                    cancel_until(0);
                    conflicts_since_restart = 0;
                    if (restart_limit < 8192) restart_limit = (restart_limit * 3) / 2;
                }
            } else {
                int next = pick_branch_lit();
                if (next == 0) {
                    model.assign(n + 1, 0);
                    for (int v = 1; v <= n; ++v) model[v] = assigns[v] == -1 ? -v : v;
                    proof.close();
                    return Result::Sat;
                }
                trail_lim.push_back((int)trail.size());
                enqueue(next, -1);
            }
        }
        proof.close();
        return Result::Unknown;
    }
};

int main(int argc, char** argv) {
    if (argc != 3) { fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n"); return 1; }
    Solver s;
    if (!s.read_dimacs(argv[1])) { cout << "c unsupported non-monotone or malformed CNF\ns UNKNOWN\n"; return 0; }
    bool has_binary_positive = false;
    int max_neg_size = 0;
    for (const auto& c : s.pos) if (c.v.size() == 2) has_binary_positive = true;
    for (const auto& c : s.neg) max_neg_size = max(max_neg_size, (int)c.v.size());
    cout << "c detected monotone Van-der-Waerden-style hitting instance vars=" << s.n
         << " positive=" << s.pos.size() << " negative=" << s.neg.size() << "\n";
    if (!has_binary_positive) {
        if (!getenv("TRY_PLAIN")) {
            cout << "c unsupported unreduced/plain instance; no SAT wins observed for this solver\ns UNKNOWN\n";
            return 0;
        }
        cout << "c TRY_PLAIN enabled; attempting local SAT search on unreduced instance\n";
    }
    if (has_binary_positive && s.n > 470) {
        cout << "c unsupported large palindromic reduction beyond current local-search range\ns UNKNOWN\n";
        return 0;
    }

    if (getenv("EXACT_PROOF_SECONDS")) {
        double exact_seconds = atof(getenv("EXACT_PROOF_SECONDS"));
        auto r = s.exact_with_proof(exact_seconds, argv[2]);
        if (r == Solver::ExactResult::Sat) {
            vector<int> model(s.n + 1, 1);
            for (int v = 1; v <= s.n; ++v) model[v] = s.sel[v] ? -v : v;
            if (s.verify_model(model)) {
                cout << "s SATISFIABLE\n";
                cout << "v";
                for (int v = 1; v <= s.n; ++v) {
                    if ((v - 1) % 20 == 0 && v != 1) cout << " 0\nv";
                    cout << ' ' << model[v];
                }
                cout << " 0\n";
                return 10;
            }
        }
        if (r == Solver::ExactResult::Unsat) {
            cout << "s UNSATISFIABLE\n";
            return 20;
        }
        cout << "s UNKNOWN\n";
        return 0;
    }

    auto print_model = [&](const vector<int>& model) {
        cout << "s SATISFIABLE\n";
        cout << "v";
        for (int v = 1; v <= s.n; ++v) {
            if ((v - 1) % 20 == 0 && v != 1) cout << " 0\nv";
            cout << ' ' << model[v];
        }
        cout << " 0\n";
    };

    int cdcl_max_vars = getenv("CDCL_MAX_VARS") ? atoi(getenv("CDCL_MAX_VARS")) : 191;
    int cdcl_max_neg = getenv("CDCL_MAX_NEG") ? atoi(getenv("CDCL_MAX_NEG")) : 20;
    if (s.n <= cdcl_max_vars && max_neg_size <= cdcl_max_neg) {
        double local_probe = getenv("LOCAL_PROBE_SECONDS") ? atof(getenv("LOCAL_PROBE_SECONDS")) : 5.0;
        if (s.solve(local_probe)) {
            vector<int> model(s.n + 1, 1);
            for (int v = 1; v <= s.n; ++v) model[v] = s.sel[v] ? -v : v;
            if (s.verify_model(model)) { print_model(model); return 10; }
        }
        double cdcl_seconds = getenv("CDCL_SECONDS") ? atof(getenv("CDCL_SECONDS")) : 535.0;
        CdclSolver cdcl(s);
        vector<int> cdcl_model;
        auto r = cdcl.solve(cdcl_seconds, argv[2], cdcl_model);
        if (r == CdclSolver::Result::Sat && s.verify_model(cdcl_model)) {
            print_model(cdcl_model);
            return 10;
        }
        if (r == CdclSolver::Result::Unsat) {
            cout << "s UNSATISFIABLE\n";
            return 20;
        }
        cout << "s UNKNOWN\n";
        return 0;
    }

    if (!s.solve(585.0)) { cout << "s UNKNOWN\n"; return 0; }
    vector<int> model(s.n + 1, 1);
    for (int v = 1; v <= s.n; ++v) model[v] = s.sel[v] ? -v : v;
    if (!s.verify_model(model)) { cout << "c internal model check failed\ns UNKNOWN\n"; return 0; }
    print_model(model);
    return 10;
}
