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

using Clock = std::chrono::steady_clock;

struct Formula {
    int n = 0;
    std::vector<std::vector<int>> clauses;
};

static double elapsed_sec(Clock::time_point start) {
    return std::chrono::duration<double>(Clock::now() - start).count();
}

static bool parse_dimacs(const char* path, Formula& f) {
    std::ifstream in(path);
    if (!in) return false;
    std::string tok;
    int declared_m = -1;
    while (in >> tok) {
        if (tok == "c") {
            std::string rest;
            std::getline(in, rest);
        } else if (tok == "p") {
            std::string fmt;
            in >> fmt >> f.n >> declared_m;
            if (fmt != "cnf" || f.n < 0 || declared_m < 0) return false;
            f.clauses.reserve(declared_m);
        } else if (tok == "%") {
            break;
        } else {
            std::vector<int> c;
            int lit = std::stoi(tok);
            while (lit != 0) {
                if (lit == 0 || std::abs(lit) > f.n) return false;
                c.push_back(lit);
                if (!(in >> lit)) return false;
            }
            f.clauses.push_back(std::move(c));
        }
    }
    return f.n > 0 && (declared_m < 0 || (int)f.clauses.size() == declared_m);
}

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

static bool check_model(const Formula& f, const std::vector<unsigned char>& val) {
    if ((int)val.size() <= f.n) return false;
    for (const auto& c : f.clauses) {
        bool ok = false;
        for (int lit : c) {
            if (lit_true(lit, val)) {
                ok = true;
                break;
            }
        }
        if (!ok) return false;
    }
    return true;
}

struct LocalSearch {
    struct Occ {
        int ci;
        bool pos;
    };
    const Formula& f;
    std::vector<std::vector<Occ>> occ;
    std::vector<unsigned char> val;
    std::vector<unsigned char> satcnt;
    std::vector<int> unsat, pos_unsat;
    std::mt19937_64 rng;
    int best_unsat_count = 1 << 28;
    std::vector<unsigned char> best_val;

    explicit LocalSearch(const Formula& ff) : f(ff), occ(ff.n + 1), val(ff.n + 1), satcnt(ff.clauses.size()), pos_unsat(ff.clauses.size(), -1) {
        for (int ci = 0; ci < (int)f.clauses.size(); ++ci)
            for (int lit : f.clauses[ci]) occ[std::abs(lit)].push_back({ci, lit > 0});
        uint64_t seed = 1469598103934665603ULL ^ (uint64_t)f.n;
        for (const auto& c : f.clauses)
            for (int lit : c) seed = (seed ^ (uint64_t)(lit + 1000003)) * 1099511628211ULL;
        rng.seed(seed);
    }

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

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

    void init_random() {
        unsat.clear();
        std::fill(pos_unsat.begin(), pos_unsat.end(), -1);
        for (int v = 1; v <= f.n; ++v) val[v] = (rng() >> 8) & 1;
        for (int ci = 0; ci < (int)f.clauses.size(); ++ci) {
            int s = 0;
            for (int lit : f.clauses[ci]) s += lit_true(lit, val);
            satcnt[ci] = (unsigned char)s;
            if (s == 0) add_unsat(ci);
        }
    }

    void flip(int v) {
        unsigned char old = val[v];
        val[v] = !old;
        for (const Occ& o : occ[v]) {
            int ci = o.ci;
            bool before = o.pos ? old : !old;
            int s = satcnt[ci];
            if (before) {
                if (s == 1) add_unsat(ci);
                satcnt[ci] = (unsigned char)(s - 1);
            } else {
                if (s == 0) rem_unsat(ci);
                satcnt[ci] = (unsigned char)(s + 1);
            }
        }
    }

    int break_count(int v) {
        int b = 0;
        for (const Occ& o : occ[v]) {
            int ci = o.ci;
            bool now = o.pos ? val[v] : !val[v];
            if (now && satcnt[ci] == 1) ++b;
        }
        return b;
    }

    int make_count(int v) {
        int m = 0;
        for (const Occ& o : occ[v]) {
            int ci = o.ci;
            if (satcnt[ci] != 0) continue;
            bool now = o.pos ? val[v] : !val[v];
            if (!now) ++m;
        }
        return m;
    }

    bool solve(double limit, Clock::time_point start, std::vector<unsigned char>& out) {
        const int m = (int)f.clauses.size();
        bool all_k4 = true;
        for (const auto& c : f.clauses) all_k4 = all_k4 && c.size() == 4;
        int max_tries = f.n > 5000 ? 200 : (all_k4 && f.n <= 2500 ? 1000 : 100);
        long long base_steps = std::max<long long>(300000, 500LL * m);
        if (f.n > 5000) base_steps = 2000000;
        if (all_k4 && f.n <= 2500) base_steps = 200000;
        for (int tr = 0; tr < max_tries && elapsed_sec(start) < limit; ++tr) {
            init_random();
            long long max_steps = base_steps * (f.n > 5000 ? 1 : (1 + tr / 8));
            for (long long step = 0; step < max_steps && elapsed_sec(start) < limit; ++step) {
                if ((int)unsat.size() < best_unsat_count) {
                    best_unsat_count = (int)unsat.size();
                    best_val = val;
                }
                if (unsat.empty()) {
                    out = val;
                    return true;
                }
                int ci = unsat[rng() % unsat.size()];
                const auto& c = f.clauses[ci];
                std::vector<int> cand0;
                int weights[8];
                int total_w = 0;
                for (int lit : c) {
                    int v = std::abs(lit);
                    int b = break_count(v);
                    if (b == 0) cand0.push_back(lit);
                    int w = 1000000 / ((b + 2) * (b + 2) * (b + 2));
                    weights[total_w++] = w;
                }
                int best_lit;
                if (!cand0.empty()) {
                    best_lit = cand0[rng() % cand0.size()];
                } else if ((rng() % 100) < 2) {
                    best_lit = c[rng() % c.size()];
                } else {
                    int sum = 0;
                    for (int i = 0; i < total_w; ++i) sum += weights[i];
                    int r = rng() % sum;
                    int pick = 0;
                    while (r >= weights[pick]) r -= weights[pick++];
                    best_lit = c[pick];
                    if ((rng() % 100) < 25) {
                        int best_score = -(1 << 28);
                        for (int lit : c) {
                            int v = std::abs(lit);
                            int sc = make_count(v) * 3 - break_count(v);
                            if (sc > best_score || (sc == best_score && (rng() & 1))) {
                                best_score = sc;
                                best_lit = lit;
                            }
                        }
                    }
                }
                flip(std::abs(best_lit));
            }
        }
        if (!best_val.empty()) out = best_val;
        return false;
    }
};

struct CDCL {
    struct Clause {
        std::vector<int> lits;
        bool learnt = false;
        bool deleted = false;
        int lbd = 0;
        double act = 0.0;
    };
    struct Watcher {
        int cref;
        int blocker;
    };
    struct ProofEvent {
        int cid;
        bool deletion;
    };
    const Formula& f;
    int n;
    std::vector<Clause> cs;
    std::vector<std::vector<Watcher>> watches;
    std::vector<signed char> assigns;
    std::vector<unsigned char> phase;
    std::vector<int> level, reason, trail;
    std::vector<unsigned char> seen;
    int qhead = 0;
    double var_inc = 1.0, clause_inc = 1.0;
    std::vector<double> activity;
    std::vector<int> proof_clauses;
    std::vector<int> proof_id;
    std::vector<ProofEvent> proof_events;
    std::vector<int> active_learnts;
    int next_proof_id = 1;
    Clock::time_point start;
    double limit;
    bool debug = false;
    long long reduce_interval = 10000;

    CDCL(const Formula& ff, Clock::time_point st, double lim, const std::vector<unsigned char>& preferred) : f(ff), n(ff.n), watches(2 * ff.n + 2), assigns(ff.n + 1, -1), phase(ff.n + 1, 1), level(ff.n + 1), reason(ff.n + 1, -1), seen(ff.n + 1), activity(ff.n + 1), start(st), limit(lim) {
        cs.reserve(ff.clauses.size() + 100000);
        proof_id.reserve(ff.clauses.size() + 100000);
        next_proof_id = (int)ff.clauses.size() + 1;
        for (const auto& c : ff.clauses) add_orig(c);
        add_table_closure();
        std::vector<int> pos(ff.n + 1), neg(ff.n + 1);
        for (const auto& c : ff.clauses) {
            for (int lit : c) {
                activity[std::abs(lit)] += 1.0;
                if (lit > 0) pos[lit]++; else neg[-lit]++;
            }
        }
        for (int v = 1; v <= ff.n; ++v) phase[v] = pos[v] >= neg[v];
        if (const char* pe = std::getenv("LKSAT_PHASE")) {
            std::string ps(pe);
            if (ps == "false") {
                for (int v = 1; v <= ff.n; ++v) phase[v] = 0;
            } else if (ps == "true") {
                for (int v = 1; v <= ff.n; ++v) phase[v] = 1;
            } else if (ps == "random") {
                uint64_t x = 88172645463393265ULL ^ (uint64_t)ff.n;
                for (const auto& c : ff.clauses)
                    for (int lit : c) x = x * 2862933555777941757ULL + (uint64_t)(lit + 1009);
                for (int v = 1; v <= ff.n; ++v) {
                    x ^= x << 7;
                    x ^= x >> 9;
                    phase[v] = x & 1;
                }
            }
        }
        if ((int)preferred.size() > ff.n) {
            for (int v = 1; v <= ff.n; ++v) phase[v] = preferred[v];
        }
        debug = std::getenv("LKSAT_DEBUG") != nullptr;
        if (const char* re = std::getenv("LKSAT_REDUCE_INTERVAL")) {
            long long v = std::atoll(re);
            if (v > 0) reduce_interval = v;
        }
    }

    int idx(int lit) const {
        int v = std::abs(lit) - 1;
        return 2 * v + (lit < 0);
    }
    signed char val_lit(int lit) const {
        signed char a = assigns[std::abs(lit)];
        if (a < 0) return -1;
        bool b = a;
        bool t = lit > 0 ? b : !b;
        return t ? 1 : 0;
    }
    int decision_level() const { return trail_lim_size; }
    int trail_lim_size = 0;
    std::vector<int> trail_lim;

    void attach(int cid) {
        auto& l = cs[cid].lits;
        if (l.size() >= 2) {
            watches[idx(l[0])].push_back({cid, l[1]});
            watches[idx(l[1])].push_back({cid, l[0]});
        }
    }
    void add_orig(std::vector<int> lits) {
        int cid = (int)cs.size();
        cs.push_back({std::move(lits), false, false, 0, 0.0});
        proof_id.push_back(0);
        if (cs.back().lits.size() >= 2) attach(cid);
    }
    bool enqueue(int lit, int from) {
        int v = std::abs(lit);
        signed char want = lit > 0 ? 1 : 0;
        if (assigns[v] >= 0) return assigns[v] == want;
        assigns[v] = want;
        phase[v] = want;
        level[v] = decision_level();
        reason[v] = from;
        trail.push_back(lit);
        return true;
    }
    int add_learned(std::vector<int> lits) {
        int cid = (int)cs.size();
        int lbd = compute_lbd(lits);
        cs.push_back({std::move(lits), true, false, lbd, 0.0});
        proof_id.push_back(next_proof_id++);
        proof_clauses.push_back(cid);
        proof_events.push_back({cid, false});
        active_learnts.push_back(cid);
        if (cs[cid].lits.size() >= 2) attach(cid);
        return cid;
    }

    static uint64_t tuple_key(const std::vector<int>& vars) {
        uint64_t key = (uint64_t)vars.size();
        for (int i = 0; i < (int)vars.size(); ++i) key |= (uint64_t)vars[i] << (4 + 16 * i);
        return key;
    }

    int compute_lbd(const std::vector<int>& lits) const {
        int cnt = 0;
        std::vector<unsigned char> used(trail_lim_size + 1);
        for (int lit : lits) {
            int lv = level[std::abs(lit)];
            if (lv >= 0 && lv < (int)used.size() && !used[lv]) {
                used[lv] = 1;
                cnt++;
            }
        }
        return cnt;
    }

    void add_table_closure() {
        struct Table {
            std::vector<int> vars;
            bool full[16] = {};
        };
        std::vector<Table> tables;
        std::unordered_map<uint64_t, int> by_key;
        tables.reserve(f.clauses.size());
        for (const auto& c : f.clauses) {
            int k = (int)c.size();
            if (k < 2 || k > 4) continue;
            std::vector<int> vars;
            vars.reserve(k);
            for (int lit : c) vars.push_back(std::abs(lit));
            std::sort(vars.begin(), vars.end());
            vars.erase(std::unique(vars.begin(), vars.end()), vars.end());
            if ((int)vars.size() != k) continue;
            uint64_t key = tuple_key(vars);
            auto it = by_key.find(key);
            int tid;
            if (it == by_key.end()) {
                tid = (int)tables.size();
                by_key.emplace(key, tid);
                tables.push_back({});
                tables.back().vars = vars;
            } else {
                tid = it->second;
            }
            int sign = 0;
            for (int lit : c) {
                int pos = (int)(std::lower_bound(vars.begin(), vars.end(), std::abs(lit)) - vars.begin());
                if (lit > 0) sign |= 1 << pos;
            }
            int forbidden = ((1 << k) - 1) ^ sign;
            tables[tid].full[forbidden] = true;
        }

        for (const auto& t : tables) {
            int k = (int)t.vars.size();
            bool active[16][16] = {};
            int all = (1 << k) - 1;
            int full_count = 0;
            for (int p = 0; p < (1 << k); ++p) {
                if (t.full[p]) {
                    active[all][p] = true;
                    full_count++;
                }
            }
            if (full_count < 2) continue;
            for (int sz = k - 1; sz >= 0; --sz) {
                for (int care = 0; care < (1 << k); ++care) {
                    if (__builtin_popcount((unsigned)care) != sz) continue;
                    for (int pat = 0; pat < (1 << k); ++pat) {
                        if (pat & ~care) continue;
                        if (active[care][pat]) continue;
                        bool ok = false;
                        for (int j = 0; j < k; ++j) {
                            if (care & (1 << j)) continue;
                            int child = care | (1 << j);
                            if (active[child][pat] && active[child][pat | (1 << j)]) {
                                ok = true;
                                break;
                            }
                        }
                        if (!ok) continue;
                        active[care][pat] = true;
                        std::vector<int> lits;
                        lits.reserve(sz);
                        for (int j = 0; j < k; ++j) {
                            if (!(care & (1 << j))) continue;
                            lits.push_back((pat & (1 << j)) ? -t.vars[j] : t.vars[j]);
                        }
                        add_learned(std::move(lits));
                    }
                }
            }
        }
    }

    int propagate() {
        while (qhead < (int)trail.size()) {
            int p = trail[qhead++];
            auto& ws = watches[idx(-p)];
            int out = 0;
            for (int ii = 0; ii < (int)ws.size(); ++ii) {
                Watcher w = ws[ii];
                if (cs[w.cref].deleted) continue;
                if (val_lit(w.blocker) == 1) {
                    ws[out++] = w;
                    continue;
                }
                int cid = w.cref;
                auto& c = cs[cid].lits;
                if (c.size() == 1) {
                    ws[out++] = w;
                    continue;
                }
                if (c[0] == -p) std::swap(c[0], c[1]);
                if (c[1] != -p) {
                    ws[out++] = w;
                    continue;
                }
                int other = c[0];
                if (val_lit(other) == 1) {
                    ws[out++] = {cid, other};
                    continue;
                }
                bool found = false;
                for (int k = 2; k < (int)c.size(); ++k) {
                    if (val_lit(c[k]) != 0) {
                        std::swap(c[1], c[k]);
                        watches[idx(c[1])].push_back({cid, other});
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    ws[out++] = {cid, other};
                    if (val_lit(other) == 0) {
                        for (++ii; ii < (int)ws.size(); ++ii) ws[out++] = ws[ii];
                        ws.resize(out);
                        return cid;
                    }
                    if (!enqueue(other, cid)) {
                        for (++ii; ii < (int)ws.size(); ++ii) ws[out++] = ws[ii];
                        ws.resize(out);
                        return cid;
                    }
                }
            }
            ws.resize(out);
        }
        return -1;
    }

    void new_decision_level() {
        trail_lim.push_back((int)trail.size());
        trail_lim_size++;
    }
    void cancel_until(int lvl) {
        if (decision_level() <= lvl) return;
        for (int c = (int)trail.size() - 1; c >= trail_lim[lvl]; --c) {
            int v = std::abs(trail[c]);
            assigns[v] = -1;
            reason[v] = -1;
        }
        qhead = trail_lim[lvl];
        trail.resize(trail_lim[lvl]);
        trail_lim.resize(lvl);
        trail_lim_size = 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;
        }
    }
    int pick_branch() {
        int best = 0;
        double ba = -1.0;
        for (int v = 1; v <= n; ++v) {
            if (assigns[v] < 0 && activity[v] > ba) {
                ba = activity[v];
                best = v;
            }
        }
        return best;
    }
    void analyze(int confl, std::vector<int>& out, int& backtrack) {
        out.clear();
        out.push_back(0);
        int pathC = 0;
        int p = 0;
        int idx_tr = (int)trail.size() - 1;
        do {
            Clause& c = cs[confl];
            if (c.learnt) c.act += clause_inc;
            for (int j = (p == 0 ? 0 : 1); j < (int)c.lits.size(); ++j) {
                int q = c.lits[j];
                int v = std::abs(q);
                if (!seen[v] && level[v] > 0) {
                    seen[v] = 1;
                    bump_var(v);
                    if (level[v] == decision_level()) pathC++;
                    else out.push_back(q);
                }
            }
            while (idx_tr >= 0 && !seen[std::abs(trail[idx_tr])]) idx_tr--;
            p = trail[idx_tr--];
            confl = reason[std::abs(p)];
            seen[std::abs(p)] = 0;
            pathC--;
        } while (pathC > 0);
        out[0] = -p;
        backtrack = 0;
        for (int i = 1; i < (int)out.size(); ++i) backtrack = std::max(backtrack, level[std::abs(out[i])]);
        for (int lit : out) seen[std::abs(lit)] = 0;
        var_inc *= 1.05;
        clause_inc *= 1.001;
    }

    bool locked_clause(int cid) const {
        for (int v = 1; v <= n; ++v)
            if (reason[v] == cid) return true;
        return false;
    }

    void reduce_db() {
        if (active_learnts.size() < 2000) return;
        std::vector<unsigned char> locked(cs.size());
        for (int v = 1; v <= n; ++v)
            if (reason[v] >= 0) locked[reason[v]] = 1;
        std::vector<int> cand;
        cand.reserve(active_learnts.size());
        std::vector<int> kept;
        kept.reserve(active_learnts.size());
        for (int cid : active_learnts) {
            if (cs[cid].deleted) continue;
            if (cs[cid].lits.size() <= 2 || cs[cid].lbd <= 2 || locked[cid]) {
                kept.push_back(cid);
            } else {
                cand.push_back(cid);
            }
        }
        if (cand.size() < 2000) {
            active_learnts.swap(kept);
            active_learnts.insert(active_learnts.end(), cand.begin(), cand.end());
            return;
        }
        std::sort(cand.begin(), cand.end(), [&](int a, int b) {
            if (cs[a].lbd != cs[b].lbd) return cs[a].lbd > cs[b].lbd;
            if (cs[a].act != cs[b].act) return cs[a].act < cs[b].act;
            return cs[a].lits.size() > cs[b].lits.size();
        });
        size_t del = cand.size() / 2;
        for (size_t i = 0; i < del; ++i) {
            cs[cand[i]].deleted = true;
            proof_events.push_back({cand[i], true});
        }
        for (size_t i = del; i < cand.size(); ++i) kept.push_back(cand[i]);
        active_learnts.swap(kept);
    }

    int solve(std::vector<unsigned char>& model) {
        for (int cid = 0; cid < (int)cs.size(); ++cid) {
            if (cs[cid].lits.empty()) {
                add_learned({});
                return 20;
            }
            if (cs[cid].lits.size() == 1 && !enqueue(cs[cid].lits[0], cid)) {
                add_learned({});
                return 20;
            }
        }
        int confl = propagate();
        if (confl >= 0) {
            add_learned({});
            return 20;
        }
        bool all_k4 = true;
        for (const auto& c : f.clauses) all_k4 = all_k4 && c.size() == 4;
        if (n <= 2500 && all_k4) {
            double probe_window = 60.0;
            if (const char* pe = std::getenv("LKSAT_PROBE_WINDOW")) {
                double v = std::atof(pe);
                if (v >= 0.0) probe_window = v;
            }
            double probe_until = std::min(limit, elapsed_sec(start) + probe_window);
            for (int round = 0; round < 10 && elapsed_sec(start) < probe_until; ++round) {
                bool changed = false;
                for (int v = 1; v <= n && elapsed_sec(start) < probe_until; ++v) {
                    if (assigns[v] >= 0) continue;
                    for (int sign = 0; sign < 2; ++sign) {
                        if (assigns[v] >= 0) break;
                        int lit = sign == 0 ? v : -v;
                        new_decision_level();
                        bool ok = enqueue(lit, -1);
                        int pc = ok ? propagate() : 0;
                        cancel_until(0);
                        if (!ok || pc >= 0) {
                            int cid = add_learned({-lit});
                            changed = true;
                            if (!enqueue(-lit, cid)) {
                                add_learned({});
                                return 20;
                            }
                            int c0 = propagate();
                            if (c0 >= 0) {
                                add_learned({});
                                return 20;
                            }
                        }
                    }
                }
                if (!changed) break;
            }
        }
        long long conflicts = 0;
        long long restart_lim = 100;
        while (true) {
            if ((conflicts & 1023) == 0 && elapsed_sec(start) > limit) return 0;
            if (debug && conflicts > 0 && (conflicts % 100000) == 0) {
                std::cerr << "c cdcl conflicts=" << conflicts
                          << " learnt_active=" << active_learnts.size()
                          << " clauses=" << cs.size()
                          << " trail=" << trail.size()
                          << " time=" << elapsed_sec(start) << "\n";
            }
            confl = propagate();
            if (confl >= 0) {
                conflicts++;
                if (decision_level() == 0) {
                    add_learned({});
                    return 20;
                }
                std::vector<int> learnt;
                int bt = 0;
                analyze(confl, learnt, bt);
                cancel_until(bt);
                int cid = add_learned(learnt);
                enqueue(cs[cid].lits[0], cid);
                if (conflicts >= restart_lim) {
                    cancel_until(0);
                    restart_lim = restart_lim * 3 / 2 + 100;
                }
                if ((conflicts % reduce_interval) == 0) reduce_db();
            } else {
                int next = pick_branch();
                if (next == 0) {
                    model.assign(n + 1, 0);
                    for (int v = 1; v <= n; ++v) model[v] = assigns[v] == 1;
                    return 10;
                }
                new_decision_level();
                enqueue(phase[next] ? next : -next, -1);
            }
        }
    }

    static std::string pb_lit(int lit) {
        std::string s = "1 ";
        if (lit < 0) s += "~";
        s += "x" + std::to_string(std::abs(lit));
        return s;
    }
    bool write_proof(const char* path) {
        FILE* out = std::fopen(path, "w");
        if (!out) return false;
        static char buf[1 << 20];
        std::setvbuf(out, buf, _IOFBF, sizeof(buf));
        std::fputs("pseudo-Boolean proof version 3.0\n", out);
        for (const auto& ev : proof_events) {
            int cid = ev.cid;
            if (ev.deletion) {
                std::fprintf(out, "del id %d ;\n", proof_id[cid]);
            } else {
                std::fputs("rup ", out);
                for (int lit : cs[cid].lits) {
                    if (lit < 0) std::fprintf(out, "1 ~x%d ", -lit);
                    else std::fprintf(out, "1 x%d ", lit);
                }
                std::fputs(">= 1 ;\n", out);
            }
        }
        std::fputs("output NONE ;\n", out);
        std::fputs("conclusion UNSAT : -1 ;\n", out);
        std::fputs("end pseudo-Boolean proof ;\n", out);
        return std::fclose(out) == 0;
    }
};

static void print_model(const std::vector<unsigned char>& val, int n) {
    std::cout << "s SATISFIABLE\n";
    std::cout << "v ";
    for (int v = 1; v <= n; ++v) {
        int lit = val[v] ? v : -v;
        std::cout << lit << ' ';
        if (v % 20 == 0 && v != n) std::cout << "0\nv ";
    }
    std::cout << "0\n";
}

int main(int argc, char** argv) {
    auto start = Clock::now();
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Formula f;
    if (!parse_dimacs(argv[1], f)) {
        std::cout << "c parse failed\ns UNKNOWN\n";
        return 0;
    }
    std::cout << "c parsed n=" << f.n << " m=" << f.clauses.size() << "\n";

    std::vector<unsigned char> model;
    bool formula_all_k4 = true;
    for (const auto& c : f.clauses) formula_all_k4 = formula_all_k4 && c.size() == 4;
    double ls_limit = f.n > 5000 ? 60.0 : ((formula_all_k4 && f.n <= 2500) ? 4.0 : 5.0);
    if (const char* e = std::getenv("LKSAT_LS_LIMIT")) ls_limit = std::atof(e);
    LocalSearch ls(f);
    if (ls.solve(ls_limit, start, model) && check_model(f, model)) {
        std::cout << "c local-search model verified\n";
        print_model(model, f.n);
        return 10;
    }
    std::cout << "c local-search best-unsat=" << ls.best_unsat_count << "\n";
    bool input_all_k4 = true;
    for (const auto& c : f.clauses) input_all_k4 = input_all_k4 && c.size() == 4;
    double k4_extend_limit = 0.0;
    if (const char* ee = std::getenv("LKSAT_K4_EXTEND_LIMIT")) {
        double v = std::atof(ee);
        if (v >= 0.0) k4_extend_limit = v;
    }
    if (input_all_k4 && f.n <= 2500 && ls.best_unsat_count <= 8 && elapsed_sec(start) < k4_extend_limit) {
        std::cout << "c extending close local-search run\n";
        if (ls.solve(k4_extend_limit, start, model) && check_model(f, model)) {
            std::cout << "c extended local-search model verified\n";
            print_model(model, f.n);
            return 10;
        }
        std::cout << "c extended local-search best-unsat=" << ls.best_unsat_count << "\n";
    }

    double cdcl_limit = 585.0;
    static const std::vector<unsigned char> no_preferred_phase;
    CDCL cdcl(f, start, cdcl_limit, no_preferred_phase);
    int res = cdcl.solve(model);
    if (res == 10) {
        if (check_model(f, model)) {
            std::cout << "c cdcl model verified\n";
            print_model(model, f.n);
            return 10;
        }
        std::cout << "c internal model check failed\ns UNKNOWN\n";
        return 0;
    }
    if (res == 20) {
        if (!cdcl.write_proof(argv[2])) {
            std::cout << "c proof write failed\ns UNKNOWN\n";
            return 0;
        }
        std::cout << "s UNSATISFIABLE\n";
        return 20;
    }
    std::cout << "s UNKNOWN\n";
    return 0;
}
