#include <algorithm>
#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <ctime>
#include <queue>
#include <sys/resource.h>
#include <vector>

namespace {

class FastInput {
public:
    explicit FastInput(const char* path) {
        f_ = std::fopen(path, "rb");
        if (!f_) {
            std::fprintf(stderr, "c could not open %s: %s\n", path, std::strerror(errno));
        }
    }
    ~FastInput() {
        if (f_) std::fclose(f_);
    }
    bool ok() const { return f_ != nullptr; }

    int get() {
        if (pos_ >= len_) {
            len_ = std::fread(buf_, 1, sizeof(buf_), f_);
            pos_ = 0;
            if (len_ == 0) return EOF;
        }
        return buf_[pos_++];
    }

    void unget() {
        if (pos_ > 0) --pos_;
    }

    void skipLine() {
        int c;
        while ((c = get()) != EOF && c != '\n') {}
    }

    bool readToken(std::string& out) {
        out.clear();
        int c;
        do {
            c = get();
            if (c == EOF) return false;
        } while (c <= ' ');
        while (c != EOF && c > ' ') {
            out.push_back(static_cast<char>(c));
            c = get();
        }
        return true;
    }

    bool readInt(int32_t& x) {
        int c;
        do {
            c = get();
            if (c == EOF) return false;
            if (c == 'c') {
                skipLine();
                continue;
            }
        } while (c <= ' ');
        int sign = 1;
        if (c == '-') {
            sign = -1;
            c = get();
        }
        int32_t v = 0;
        while (c >= '0' && c <= '9') {
            v = v * 10 + (c - '0');
            c = get();
        }
        x = sign * v;
        return true;
    }

private:
    FILE* f_ = nullptr;
    unsigned char buf_[1 << 20];
    size_t pos_ = 0;
    size_t len_ = 0;
};

struct Formula {
    uint32_t nvars = 0;
    uint32_t nclauses = 0;
    std::vector<uint32_t> group_start;  // non-unit clause range by max var
    std::vector<uint32_t> clause_off;   // offsets into lits
    std::vector<int32_t> lits;
    std::vector<int32_t> units;
};

uint32_t abs_lit(int32_t x) {
    return static_cast<uint32_t>(x < 0 ? -static_cast<int64_t>(x) : x);
}

bool parseDimacs(const char* path, Formula& F) {
    FastInput in(path);
    if (!in.ok()) return false;

    std::string tok;
    while (in.readToken(tok)) {
        if (tok == "c") {
            in.skipLine();
            continue;
        }
        if (tok == "p") {
            std::string cnf, sv, sc;
            if (!in.readToken(cnf) || !in.readToken(sv) || !in.readToken(sc)) return false;
            F.nvars = static_cast<uint32_t>(std::stoul(sv));
            F.nclauses = static_cast<uint32_t>(std::stoul(sc));
            break;
        }
    }
    if (F.nvars == 0) return false;

    F.clause_off.reserve(static_cast<size_t>(F.nclauses) + 1);
    F.clause_off.push_back(0);
    F.units.reserve(F.nclauses / 32 + 16);

    std::vector<int32_t> clause;
    clause.reserve(160);
    uint32_t current_max = 0;
    uint32_t nonunit_count = 0;
    uint32_t clauses_seen = 0;
    bool sorted = true;

    int32_t lit = 0;
    while (in.readInt(lit)) {
        if (lit == 0) {
            ++clauses_seen;
            if (clause.empty()) {
                // Empty clauses are unsupported for SAT production.
                return false;
            }
            if (clause.size() == 1) {
                F.units.push_back(clause[0]);
            } else {
                uint32_t mx = 0;
                for (int32_t l : clause) mx = std::max(mx, abs_lit(l));
                if (mx < current_max) {
                    sorted = false;
                    break;
                }
                if (mx > current_max) current_max = mx;
                F.lits.insert(F.lits.end(), clause.begin(), clause.end());
                F.clause_off.push_back(static_cast<uint32_t>(F.lits.size()));
                ++nonunit_count;
            }
            clause.clear();
        } else {
            clause.push_back(lit);
        }
    }
    if (!sorted) {
        std::fprintf(stderr, "c unsupported: non-unit clauses are not sorted by max variable\n");
        return false;
    }
    return clauses_seen == F.nclauses;
}

struct XorShift64 {
    uint64_t s;
    explicit XorShift64(uint64_t seed) : s(seed ? seed : 88172645463325252ull) {}
    uint64_t next() {
        uint64_t x = s;
        x ^= x << 7;
        x ^= x >> 9;
        s = x;
        return x;
    }
};

struct Solver {
    const Formula& F;
    std::vector<int8_t> val;       // -1 unknown, 0 false, 1 true
    std::vector<uint32_t> trail;
    XorShift64 rng;
    uint64_t force_calls = 0;
    uint64_t candidate_tries = 0;
    bool prefer_true = false;
    bool reverse_units = false;
    uint64_t node_limit = 2000000;
    uint64_t nodes = 0;
    double deadline = 0.0;

    struct Task {
        uint8_t kind; // 0 literal, 1 clause
        int32_t lit;
        uint32_t cid;
    };
    struct TaskNode {
        Task task;
        uint32_t prev;
    };
    static constexpr uint32_t NIL = UINT32_MAX;
    std::vector<TaskNode> task_nodes;
    uint32_t task_head = NIL;

    explicit Solver(const Formula& formula, uint64_t seed)
        : F(formula), val(static_cast<size_t>(formula.nvars) + 1, -1), rng(seed) {}

    void undo(size_t checkpoint) {
        while (trail.size() > checkpoint) {
            val[trail.back()] = -1;
            trail.pop_back();
        }
    }

    int8_t litVal(int32_t lit) const {
        uint32_t v = abs_lit(lit);
        int8_t x = val[v];
        if (x < 0) return -1;
        bool b = x != 0;
        if (lit < 0) b = !b;
        return b ? 1 : 0;
    }

    uint32_t groupSize(uint32_t v) const {
        return F.group_start[v + 1] - F.group_start[v];
    }

    bool clauseSatisfied(uint32_t cid) const {
        uint32_t b = F.clause_off[cid], e = F.clause_off[cid + 1];
        for (uint32_t i = b; i < e; ++i) {
            if (litVal(F.lits[i]) == 1) return true;
        }
        return false;
    }

    bool forceLitPublic(int32_t lit) {
        size_t cp = trail.size();
        if (forceLit(lit)) return true;
        undo(cp);
        return false;
    }

    bool forceLit(int32_t lit) {
        ++force_calls;
        uint32_t v = abs_lit(lit);
        int8_t want = lit > 0 ? 1 : 0;
        int8_t cur = val[v];
        if (cur >= 0) return cur == want;

        val[v] = want;
        trail.push_back(v);

        uint32_t gs = F.group_start[v], ge = F.group_start[v + 1];
        for (uint32_t cid = gs; cid < ge; ++cid) {
            if (clauseSatisfied(cid)) continue;
            if (!satisfyClause(cid)) return false;
        }
        return true;
    }

    bool assignLit(int32_t lit) {
        ++force_calls;
        uint32_t v = abs_lit(lit);
        int8_t want = lit > 0 ? 1 : 0;
        int8_t cur = val[v];
        if (cur >= 0) return cur == want;
        val[v] = want;
        trail.push_back(v);
        uint32_t gs = F.group_start[v], ge = F.group_start[v + 1];
        for (uint32_t cid = gs; cid < ge; ++cid) {
            if (!clauseSatisfied(cid)) {
                pushTask(Task{1, 0, cid});
            }
        }
        return true;
    }

    void pushTask(Task t) {
        task_nodes.push_back(TaskNode{t, task_head});
        task_head = static_cast<uint32_t>(task_nodes.size() - 1);
    }

    Task popTask() {
        TaskNode node = task_nodes[task_head];
        task_head = node.prev;
        return node.task;
    }

    bool satisfyClause(uint32_t cid) {
        uint32_t b = F.clause_off[cid], e = F.clause_off[cid + 1];
        int32_t small[192];
        std::vector<int32_t> heap;
        uint32_t n = 0;
        for (uint32_t i = b; i < e; ++i) {
            int32_t lit = F.lits[i];
            int8_t lv = litVal(lit);
            if (lv == 1) return true;
            if (lv < 0) {
                if (n < sizeof(small) / sizeof(small[0])) small[n++] = lit;
                else heap.push_back(lit);
            }
        }
        if (n == 0 && heap.empty()) return false;

        auto score = [&](int32_t lit) -> uint64_t {
            uint32_t v = abs_lit(lit);
            uint64_t g = groupSize(v);
            uint64_t h = (static_cast<uint64_t>(v) * 0x9e3779b97f4a7c15ull) ^
                         (lit < 0 ? 0xbf58476d1ce4e5b9ull : 0x94d049bb133111ebull) ^
                         rng.s;
            // Prefer cheap justifications; randomize ties and long symmetric clauses.
            return (g << 48) ^ (h & ((1ull << 48) - 1));
        };
        auto try_lit = [&](int32_t cand) -> bool {
            ++candidate_tries;
            size_t cp = trail.size();
            if (forceLit(cand)) return true;
            undo(cp);
            return false;
        };

        if (heap.empty()) {
            std::sort(small, small + n, [&](int32_t a, int32_t b) { return score(a) < score(b); });
            for (uint32_t i = 0; i < n; ++i) {
                if (try_lit(small[i])) return true;
            }
        } else {
            heap.insert(heap.end(), small, small + n);
            std::sort(heap.begin(), heap.end(), [&](int32_t a, int32_t b) { return score(a) < score(b); });
            for (int32_t cand : heap) {
                if (try_lit(cand)) return true;
            }
        }
        return false;
    }

    uint64_t candScore(int32_t lit) const {
        uint32_t v = abs_lit(lit);
        uint64_t g = groupSize(v);
        uint64_t h = (static_cast<uint64_t>(v) * 0x9e3779b97f4a7c15ull) ^
                     (lit < 0 ? 0xbf58476d1ce4e5b9ull : 0x94d049bb133111ebull) ^
                     rng.s;
        if (prefer_true && lit > 0) h &= ~0xffffull;
        return (g << 48) ^ (h & ((1ull << 48) - 1));
    }

    static double nowSec() {
        timespec ts;
        clock_gettime(CLOCK_MONOTONIC, &ts);
        return static_cast<double>(ts.tv_sec) + 1e-9 * static_cast<double>(ts.tv_nsec);
    }

    bool search() {
        if (++nodes > node_limit) return false;
        if ((nodes & 8191ull) == 0 && deadline > 0.0 && nowSec() > deadline) return false;
        int32_t small[256];
        std::vector<int32_t> heap;
        while (task_head != NIL) {
            Task t = popTask();
            if (t.kind == 0) {
                if (!assignLit(t.lit)) return false;
                continue;
            }
            uint32_t b = F.clause_off[t.cid], e = F.clause_off[t.cid + 1];
            uint32_t n = 0;
            heap.clear();
            bool sat = false;
            for (uint32_t i = b; i < e; ++i) {
                int32_t lit = F.lits[i];
                int8_t lv = litVal(lit);
                if (lv == 1) {
                    sat = true;
                    break;
                }
                if (lv < 0) {
                    if (n < sizeof(small) / sizeof(small[0])) small[n++] = lit;
                    else heap.push_back(lit);
                }
            }
            if (sat) continue;
            if (n == 0 && heap.empty()) return false;

            auto tryCandidate = [&](int32_t cand) -> bool {
                ++candidate_tries;
                size_t cp_trail = trail.size();
                size_t cp_nodes = task_nodes.size();
                uint32_t cp_head = task_head;
                if (assignLit(cand) && search()) return true;
                undo(cp_trail);
                task_nodes.resize(cp_nodes);
                task_head = cp_head;
                return false;
            };

            if (heap.empty()) {
                std::sort(small, small + n, [&](int32_t a, int32_t b) {
                    return candScore(a) < candScore(b);
                });
                if (n == 1) {
                    if (!assignLit(small[0])) return false;
                    continue;
                }
                for (uint32_t i = 0; i < n; ++i) {
                    if (tryCandidate(small[i])) return true;
                }
            } else {
                heap.insert(heap.end(), small, small + n);
                std::sort(heap.begin(), heap.end(), [&](int32_t a, int32_t b) {
                    return candScore(a) < candScore(b);
                });
                if (heap.size() == 1) {
                    if (!assignLit(heap[0])) return false;
                    continue;
                }
                for (int32_t cand : heap) {
                    if (tryCandidate(cand)) return true;
                }
            }
            return false;
        }
        return true;
    }

    bool groupOkWith(uint32_t v, int8_t zval) {
        int8_t old = val[v];
        val[v] = zval;
        bool ok = true;
        uint32_t gs = F.group_start[v], ge = F.group_start[v + 1];
        for (uint32_t cid = gs; cid < ge; ++cid) {
            if (!clauseSatisfied(cid)) {
                ok = false;
                break;
            }
        }
        val[v] = old;
        return ok;
    }

    bool forceUnits(uint32_t* failed_index = nullptr, int32_t* failed_lit = nullptr) {
        if (!reverse_units) {
            for (uint32_t i = 0; i < F.units.size(); ++i) {
                int32_t u = F.units[i];
                if (!forceLitPublic(u)) {
                    if (failed_index) *failed_index = i;
                    if (failed_lit) *failed_lit = u;
                    return false;
                }
            }
        } else {
            for (size_t i = F.units.size(); i > 0; --i) {
                int32_t u = F.units[i - 1];
                if (!forceLitPublic(u)) {
                    if (failed_index) *failed_index = static_cast<uint32_t>(i - 1);
                    if (failed_lit) *failed_lit = u;
                    return false;
                }
            }
        }
        return true;
    }

    bool solveUnitsBySearch() {
        task_nodes.clear();
        task_head = NIL;
        task_nodes.reserve(F.units.size() + 4096);
        if (!reverse_units) {
            for (size_t i = F.units.size(); i > 0; --i) {
                pushTask(Task{0, F.units[i - 1], 0});
            }
        } else {
            for (int32_t u : F.units) {
                pushTask(Task{0, u, 0});
            }
        }
        return search();
    }

    bool complete() {
        for (uint32_t v = 1; v <= F.nvars; ++v) {
            if (val[v] >= 0) continue;
            uint32_t gs = F.group_start[v], ge = F.group_start[v + 1];
            if (gs == ge) {
                bool bit = prefer_true ? ((rng.next() & 7) == 0) : false;
                val[v] = bit ? 1 : 0;
                continue;
            }
            bool ok0 = groupOkWith(v, 0);
            bool ok1 = groupOkWith(v, 1);
            if (!ok0 && !ok1) return false;
            if (ok0 && ok1) {
                val[v] = (prefer_true && (rng.next() & 1)) ? 1 : 0;
            } else {
                val[v] = ok1 ? 1 : 0;
            }
        }
        return true;
    }

    bool verify(uint64_t& bad_units, uint64_t& bad_clauses) const {
        bad_units = bad_clauses = 0;
        for (int32_t u : F.units) {
            if (litVal(u) != 1) ++bad_units;
        }
        uint32_t n = static_cast<uint32_t>(F.clause_off.size() - 1);
        for (uint32_t cid = 0; cid < n; ++cid) {
            if (!clauseSatisfied(cid)) ++bad_clauses;
        }
        return bad_units == 0 && bad_clauses == 0;
    }
};

void printModel(const std::vector<int8_t>& val, uint32_t nvars) {
    std::puts("s SATISFIABLE");
    constexpr size_t LIM = 1 << 20;
    std::string out;
    out.reserve(LIM + 128);
    out += "v";
    for (uint32_t v = 1; v <= nvars; ++v) {
        char buf[32];
        int lit = val[v] ? static_cast<int>(v) : -static_cast<int>(v);
        int len = std::snprintf(buf, sizeof(buf), " %d", lit);
        if (out.size() + static_cast<size_t>(len) + 4 > LIM) {
            out += " 0\n";
            std::fwrite(out.data(), 1, out.size(), stdout);
            out.clear();
            out += "v";
        }
        out.append(buf, static_cast<size_t>(len));
    }
    out += " 0\n";
    std::fwrite(out.data(), 1, out.size(), stdout);
}

struct CDCLSolver {
    static constexpr uint32_t NIL = UINT32_MAX;
    const Formula& F;
    uint32_t orig_clauses;
    std::vector<uint32_t> head;
    std::vector<uint32_t> next_watch;
    std::vector<int32_t> watch_lit;
    std::vector<uint32_t> learnt_off;
    std::vector<int32_t> learnt_lits;
    std::vector<int8_t> val;
    std::vector<int8_t> phase;
    std::vector<uint32_t> level;
    std::vector<uint32_t> reason;
    std::vector<int32_t> trail;
    std::vector<uint32_t> trail_lim;
    size_t qhead = 0;
    std::vector<double> activity;
    double var_inc = 1.0;
    double var_decay = 0.95;
    std::priority_queue<std::pair<double, uint32_t>> heap;
    uint32_t next_decision = 1;
    uint64_t conflicts = 0;
    uint64_t decisions = 0;
    uint64_t propagations = 0;
    double deadline = 0.0;
    uint64_t conflict_limit = 200000;

    explicit CDCLSolver(const Formula& formula)
        : F(formula),
          orig_clauses(static_cast<uint32_t>(formula.clause_off.size() - 1)),
          head(static_cast<size_t>(2) * (formula.nvars + 1), NIL),
          val(static_cast<size_t>(formula.nvars) + 1, -1),
          phase(static_cast<size_t>(formula.nvars) + 1, 0),
          level(static_cast<size_t>(formula.nvars) + 1, 0),
          reason(static_cast<size_t>(formula.nvars) + 1, NIL),
          activity(static_cast<size_t>(formula.nvars) + 1, 0.0) {
        next_watch.reserve(static_cast<size_t>(2) * orig_clauses + 1024);
        watch_lit.reserve(static_cast<size_t>(2) * orig_clauses + 1024);
        learnt_off.push_back(0);
    }

    static double nowSec() {
        timespec ts;
        clock_gettime(CLOCK_MONOTONIC, &ts);
        return static_cast<double>(ts.tv_sec) + 1e-9 * static_cast<double>(ts.tv_nsec);
    }

    uint32_t litIndex(int32_t lit) const {
        uint32_t v = abs_lit(lit);
        return (v << 1) ^ (lit < 0 ? 1u : 0u);
    }

    int8_t litVal(int32_t lit) const {
        uint32_t v = abs_lit(lit);
        int8_t x = val[v];
        if (x < 0) return -1;
        bool b = x != 0;
        if (lit < 0) b = !b;
        return b ? 1 : 0;
    }

    uint32_t decisionLevel() const {
        return static_cast<uint32_t>(trail_lim.size());
    }

    void clauseRange(uint32_t cid, const int32_t*& b, const int32_t*& e) const {
        if (cid < orig_clauses) {
            b = F.lits.data() + F.clause_off[cid];
            e = F.lits.data() + F.clause_off[cid + 1];
        } else {
            uint32_t k = cid - orig_clauses;
            b = learnt_lits.data() + learnt_off[k];
            e = learnt_lits.data() + learnt_off[k + 1];
        }
    }

    void addWatch(uint32_t wid, int32_t lit) {
        watch_lit[wid] = lit;
        uint32_t idx = litIndex(lit);
        next_watch[wid] = head[idx];
        head[idx] = wid;
    }

    void initWatches() {
        for (uint32_t cid = 0; cid < orig_clauses; ++cid) {
            uint32_t b = F.clause_off[cid], e = F.clause_off[cid + 1];
            if (e - b < 2) continue;
            uint32_t w0 = static_cast<uint32_t>(watch_lit.size());
            watch_lit.push_back(0);
            next_watch.push_back(NIL);
            uint32_t w1 = static_cast<uint32_t>(watch_lit.size());
            watch_lit.push_back(0);
            next_watch.push_back(NIL);
            (void)w1;
            addWatch(w0, F.lits[b]);
            addWatch(w0 ^ 1u, F.lits[b + 1]);
        }
    }

    bool enqueue(int32_t lit, uint32_t why) {
        uint32_t v = abs_lit(lit);
        int8_t want = lit > 0 ? 1 : 0;
        int8_t cur = val[v];
        if (cur >= 0) return cur == want;
        val[v] = want;
        phase[v] = want;
        level[v] = decisionLevel();
        reason[v] = why;
        trail.push_back(lit);
        return true;
    }

    uint32_t propagate() {
        while (qhead < trail.size()) {
            int32_t lit = trail[qhead++];
            ++propagations;
            int32_t false_lit = -lit;
            uint32_t idx = litIndex(false_lit);
            uint32_t* p = &head[idx];
            uint32_t wid = *p;
            while (wid != NIL) {
                uint32_t cid = wid >> 1;
                uint32_t other_wid = wid ^ 1u;
                int32_t other = watch_lit[other_wid];
                if (litVal(other) == 1) {
                    p = &next_watch[wid];
                    wid = next_watch[wid];
                    continue;
                }
                const int32_t* b;
                const int32_t* e;
                clauseRange(cid, b, e);
                bool moved = false;
                for (const int32_t* it = b; it != e; ++it) {
                    int32_t cand = *it;
                    if (cand == other || cand == false_lit) continue;
                    if (litVal(cand) != 0) {
                        *p = next_watch[wid];
                        addWatch(wid, cand);
                        wid = *p;
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;
                if (litVal(other) == 0) {
                    return cid;
                }
                if (!enqueue(other, cid)) {
                    return cid;
                }
                p = &next_watch[wid];
                wid = next_watch[wid];
            }
        }
        return NIL;
    }

    void newDecisionLevel() {
        trail_lim.push_back(static_cast<uint32_t>(trail.size()));
    }

    void cancelUntil(uint32_t lvl) {
        if (decisionLevel() <= lvl) return;
        uint32_t target = (lvl == 0) ? 0 : trail_lim[lvl];
        for (size_t i = trail.size(); i > target; --i) {
            uint32_t v = abs_lit(trail[i - 1]);
            val[v] = -1;
            reason[v] = NIL;
            level[v] = 0;
        }
        trail.resize(target);
        qhead = std::min(qhead, trail.size());
        trail_lim.resize(lvl);
    }

    void bumpVar(uint32_t v) {
        activity[v] += var_inc;
        heap.push({activity[v], v});
        if (activity[v] > 1e100) {
            for (uint32_t i = 1; i <= F.nvars; ++i) activity[i] *= 1e-100;
            var_inc *= 1e-100;
        }
    }

    uint32_t addLearnt(const std::vector<int32_t>& clause) {
        if (clause.size() == 1) return NIL;
        uint32_t cid = orig_clauses + static_cast<uint32_t>(learnt_off.size() - 1);
        learnt_lits.insert(learnt_lits.end(), clause.begin(), clause.end());
        learnt_off.push_back(static_cast<uint32_t>(learnt_lits.size()));
        uint32_t w0 = static_cast<uint32_t>(watch_lit.size());
        watch_lit.push_back(0);
        next_watch.push_back(NIL);
        watch_lit.push_back(0);
        next_watch.push_back(NIL);
        addWatch(w0, clause[0]);
        addWatch(w0 ^ 1u, clause[1]);
        return cid;
    }

    bool analyze(uint32_t confl, std::vector<int32_t>& learnt, uint32_t& backtrack_level) {
        learnt.clear();
        learnt.push_back(0);
        std::vector<uint8_t> seen(static_cast<size_t>(F.nvars) + 1, 0);
        uint32_t pathC = 0;
        int32_t p = 0;
        int idx = static_cast<int>(trail.size()) - 1;
        uint32_t cid = confl;
        bool first_clause = true;
        do {
            const int32_t* b;
            const int32_t* e;
            clauseRange(cid, b, e);
            for (const int32_t* it = b; it != e; ++it) {
                int32_t q = *it;
                uint32_t v = abs_lit(q);
                if (!first_clause && v == abs_lit(p)) continue;
                if (!seen[v] && level[v] > 0) {
                    seen[v] = 1;
                    bumpVar(v);
                    if (level[v] == decisionLevel()) {
                        ++pathC;
                    } else {
                        learnt.push_back(q);
                    }
                }
            }
            while (idx >= 0 && !seen[abs_lit(trail[idx])]) --idx;
            if (idx < 0) return false;
            p = trail[idx];
            uint32_t pv = abs_lit(p);
            seen[pv] = 0;
            cid = reason[pv];
            --idx;
            if (pathC == 0) return false;
            --pathC;
            first_clause = false;
            if (pathC > 0 && cid == NIL) return false;
        } while (pathC > 0);
        learnt[0] = -p;

        backtrack_level = 0;
        if (learnt.size() == 1) {
            backtrack_level = 0;
        } else {
            uint32_t best_i = 1;
            uint32_t best_l = level[abs_lit(learnt[1])];
            for (uint32_t i = 2; i < learnt.size(); ++i) {
                uint32_t l = level[abs_lit(learnt[i])];
                if (l > best_l) {
                    best_l = l;
                    best_i = i;
                }
            }
            std::swap(learnt[1], learnt[best_i]);
            backtrack_level = best_l;
        }
        var_inc *= (1.0 / var_decay);
        return true;
    }

    uint32_t pickBranchVar() {
        while (!heap.empty()) {
            uint32_t v = heap.top().second;
            double a = heap.top().first;
            heap.pop();
            if (val[v] < 0 && activity[v] == a) return v;
        }
        while (next_decision <= F.nvars && val[next_decision] >= 0) ++next_decision;
        if (next_decision <= F.nvars) return next_decision++;
        return 0;
    }

    bool solve() {
        initWatches();
        for (int32_t u : F.units) {
            if (!enqueue(u, NIL)) return false;
        }
        uint32_t confl = propagate();
        if (confl != NIL) return false;
        std::vector<int32_t> learnt;
        while (true) {
            if ((conflicts & 1023ull) == 0 && deadline > 0.0 && nowSec() > deadline) return false;
            confl = propagate();
            if (confl != NIL) {
                ++conflicts;
                if (decisionLevel() == 0) return false;
                if (conflicts > conflict_limit) return false;
                uint32_t bt = 0;
                if (!analyze(confl, learnt, bt)) return false;
                cancelUntil(bt);
                if (learnt.size() == 1) {
                    if (!enqueue(learnt[0], NIL)) return false;
                } else {
                    uint32_t cid = addLearnt(learnt);
                    if (!enqueue(learnt[0], cid)) return false;
                }
            } else {
                uint32_t v = pickBranchVar();
                if (v == 0) return true;
                newDecisionLevel();
                ++decisions;
                int32_t lit = phase[v] ? static_cast<int32_t>(v) : -static_cast<int32_t>(v);
                if (!enqueue(lit, NIL)) return false;
            }
        }
    }

    bool verify(uint64_t& bad_units, uint64_t& bad_clauses) const {
        bad_units = bad_clauses = 0;
        auto lv = [&](int32_t lit) -> int8_t {
            uint32_t v = abs_lit(lit);
            int8_t x = val[v];
            if (x < 0) x = 0;
            bool b = x != 0;
            if (lit < 0) b = !b;
            return b ? 1 : 0;
        };
        for (int32_t u : F.units) if (lv(u) != 1) ++bad_units;
        for (uint32_t cid = 0; cid < orig_clauses; ++cid) {
            bool sat = false;
            for (uint32_t i = F.clause_off[cid]; i < F.clause_off[cid + 1]; ++i) {
                if (lv(F.lits[i]) == 1) {
                    sat = true;
                    break;
                }
            }
            if (!sat) ++bad_clauses;
        }
        return bad_units == 0 && bad_clauses == 0;
    }
};

} // namespace

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    rlimit rl;
    if (getrlimit(RLIMIT_STACK, &rl) == 0) {
        rl.rlim_cur = rl.rlim_max;
        setrlimit(RLIMIT_STACK, &rl);
    }

    Formula F;
    if (!parseDimacs(argv[1], F)) {
        std::puts("s UNKNOWN");
        return 0;
    }
    std::fprintf(stderr,
                 "c parsed vars=%u clauses=%u nonunit=%zu units=%zu lits=%zu\n",
                 F.nvars, F.nclauses, F.clause_off.size() - 1, F.units.size(), F.lits.size());

    {
        CDCLSolver C(F);
        C.deadline = CDCLSolver::nowSec() + 560.0;
        if (const char* s = std::getenv("LYM_CDCL_SECONDS")) C.deadline = CDCLSolver::nowSec() + std::strtod(s, nullptr);
        if (const char* s = std::getenv("LYM_CDCL_CONFLICTS")) C.conflict_limit = std::strtoull(s, nullptr, 10);
        bool ok = C.solve();
        uint64_t bad_u = 0, bad_c = 0;
        if (ok) ok = C.verify(bad_u, bad_c);
        std::fprintf(stderr,
                     "c cdcl ok=%d conflicts=%llu decisions=%llu props=%llu learnt=%zu bad_units=%llu bad_clauses=%llu\n",
                     ok ? 1 : 0,
                     static_cast<unsigned long long>(C.conflicts),
                     static_cast<unsigned long long>(C.decisions),
                     static_cast<unsigned long long>(C.propagations),
                     C.learnt_off.size() - 1,
                     static_cast<unsigned long long>(bad_u),
                     static_cast<unsigned long long>(bad_c));
        if (ok) {
            printModel(C.val, F.nvars);
            return 10;
        }
        std::puts("s UNKNOWN");
        return 0;
    }

    // A few deterministic/randomized justification orders.  The formula family is
    // SAT-heavy; every SAT claim is still checked against all stored clauses.
    uint64_t env_limit = 0;
    if (const char* s = std::getenv("LYM_NODE_LIMIT")) env_limit = std::strtoull(s, nullptr, 10);
    double env_seconds = 0.0;
    if (const char* s = std::getenv("LYM_ATTEMPT_SECONDS")) env_seconds = std::strtod(s, nullptr);
    for (uint32_t attempt = 0; attempt < 12; ++attempt) {
        uint64_t seed = 0x4d44354551554c43ull ^ (static_cast<uint64_t>(F.nvars) << 17) ^
                        (static_cast<uint64_t>(attempt) * 0x9e3779b97f4a7c15ull);
        Solver S(F, seed);
        S.prefer_true = (attempt & 4) != 0;
        S.reverse_units = (attempt & 1) != 0;
        S.node_limit = env_limit ? env_limit : (2000000ull + static_cast<uint64_t>(attempt) * 1000000ull);
        S.deadline = Solver::nowSec() + (env_seconds > 0.0 ? env_seconds : 35.0);
        bool ok = S.solveUnitsBySearch() && S.complete();
        uint64_t bad_u = 0, bad_c = 0;
        if (ok) ok = S.verify(bad_u, bad_c);
        std::fprintf(stderr,
                     "c attempt=%u ok=%d assigned=%zu calls=%llu tries=%llu nodes=%llu bad_units=%llu bad_clauses=%llu\n",
                     attempt, ok ? 1 : 0, S.trail.size(),
                     static_cast<unsigned long long>(S.force_calls),
                     static_cast<unsigned long long>(S.candidate_tries),
                     static_cast<unsigned long long>(S.nodes),
                     static_cast<unsigned long long>(bad_u),
                     static_cast<unsigned long long>(bad_c));
        if (ok) {
            printModel(S.val, F.nvars);
            return 10;
        }
    }

    std::puts("s UNKNOWN");
    return 0;
}
