#include <algorithm>
#include <array>
#include <chrono>
#include <atomic>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <mutex>
#include <numeric>
#include <string>
#include <thread>
#include <vector>

using Clock = std::chrono::steady_clock;

struct XorShift {
    uint64_t s;
    explicit XorShift(uint64_t seed) : s(seed ? seed : 0x9e3779b97f4a7c15ULL) {}
    uint64_t next() {
        uint64_t x = s;
        x ^= x << 7;
        x ^= x >> 9;
        s = x;
        return x;
    }
    int randint(int n) { return (int)(next() % (uint64_t)n); }
    double unit() { return (next() >> 11) * (1.0 / 9007199254740992.0); }
};

struct Formula {
    struct Occ {
        int ci;
        int pos;
        int lit;
    };
    int n = 0;
    int m = 0;
    std::vector<std::array<int, 3>> clauses;
    std::vector<std::vector<int>> occ;
    std::vector<std::vector<Occ>> occs;
};

static bool read_dimacs(const char* path, Formula& f) {
    std::ifstream in(path);
    if (!in) return false;
    std::string tok;
    while (in >> tok) {
        if (tok == "c") {
            std::string rest;
            std::getline(in, rest);
        } else if (tok == "p") {
            std::string cnf;
            in >> cnf >> f.n >> f.m;
            if (cnf != "cnf" || f.n <= 0 || f.m < 0) return false;
            f.clauses.reserve(f.m);
        } else {
            int first = std::stoi(tok);
            std::vector<int> lits;
            lits.push_back(first);
            int x;
            while (in >> x) {
                if (x == 0) break;
                lits.push_back(x);
            }
            if (lits.empty() || (int)lits.size() > 3) return false;
            while ((int)lits.size() < 3) lits.push_back(lits.back());
            for (int l : lits) {
                if (l == 0 || std::abs(l) > f.n) return false;
            }
            f.clauses.push_back({lits[0], lits[1], lits[2]});
        }
    }
    f.m = (int)f.clauses.size();
    f.occ.assign(f.n + 1, {});
    f.occs.assign(f.n + 1, {});
    for (int i = 0; i < f.m; ++i) {
        for (int p = 0; p < 3; ++p) {
            int l = f.clauses[i][p];
            f.occ[std::abs(l)].push_back(i);
            f.occs[std::abs(l)].push_back({i, p, l});
        }
    }
    return f.n > 0 && f.m > 0;
}

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

static bool verify(const Formula& f, const std::vector<unsigned char>& a) {
    if ((int)a.size() != f.n + 1) return false;
    for (const auto& c : f.clauses) {
        if (!lit_true(c[0], a) && !lit_true(c[1], a) && !lit_true(c[2], a)) return false;
    }
    return true;
}

static void print_sat(const Formula& f, const std::vector<unsigned char>& a) {
    std::puts("s SATISFIABLE");
    std::printf("v ");
    int col = 2;
    for (int i = 1; i <= f.n; ++i) {
        int lit = a[i] ? i : -i;
        std::printf("%d ", lit);
        if (++col >= 18 && i != f.n) {
            std::printf("0\nv ");
            col = 2;
        }
    }
    std::printf("0\n");
}

static bool first_block_model(const Formula& f, std::vector<unsigned char>& a) {
    if (f.m < f.n) return false;
    std::vector<unsigned char> seen(f.n + 1, 0);
    a.assign(f.n + 1, 0);
    for (int i = 0; i < f.n; ++i) {
        int lit = f.clauses[i][0];
        int v = std::abs(lit);
        if (v < 1 || v > f.n || seen[v]) return false;
        seen[v] = 1;
        a[v] = (lit > 0);
    }
    for (int v = 1; v <= f.n; ++v) if (!seen[v]) return false;
    return verify(f, a);
}

static double logaddexp2(double a, double b) {
    if (a < b) std::swap(a, b);
    if (b < -1e90) return a;
    return a + std::log1p(std::exp(b - a));
}

static double clamp_llr(double x) {
    if (x < -40.0) return -40.0;
    if (x > 40.0) return 40.0;
    return x;
}

static int clause_pattern(const std::array<int, 3>& c, const std::vector<unsigned char>& a) {
    int pat = 0;
    for (int p = 0; p < 3; ++p) {
        int lit = c[p];
        if (a[std::abs(lit)] == (lit > 0)) pat |= 1 << p;
    }
    return pat;
}

static double pattern_score(const Formula& f, const std::vector<unsigned char>& a,
                            const std::array<double, 8>& theta) {
    double s = 0.0;
    for (const auto& c : f.clauses) s += theta[clause_pattern(c, a)];
    return s;
}

static void maybe_flip_global_by_pattern(const Formula& f, std::vector<unsigned char>& a,
                                         const std::array<double, 8>& theta) {
    std::vector<unsigned char> b = a;
    for (int v = 1; v <= f.n; ++v) b[v] ^= 1;
    if (pattern_score(f, b, theta) > pattern_score(f, a, theta)) a.swap(b);
}

static void pattern_local_search(const Formula& f, std::vector<unsigned char>& a,
                                 const std::array<double, 8>& theta, XorShift& rng,
                                 int sweeps = 140) {
    std::vector<std::array<int, 3>> occ_pos(f.n + 1);
    std::vector<std::vector<std::pair<int, int>>> occ(f.n + 1);
    for (int ci = 0; ci < f.m; ++ci) {
        for (int p = 0; p < 3; ++p) occ[std::abs(f.clauses[ci][p])].push_back({ci, p});
    }
    std::vector<int> pat(f.m);
    for (int ci = 0; ci < f.m; ++ci) pat[ci] = clause_pattern(f.clauses[ci], a);
    std::vector<int> order(f.n);
    std::iota(order.begin(), order.end(), 1);
    std::vector<unsigned char> best = a;
    double cur_score = 0.0;
    for (int p : pat) cur_score += theta[p];
    double best_score = cur_score;

    for (int sweep = 0; sweep < sweeps; ++sweep) {
        for (int i = f.n - 1; i > 0; --i) std::swap(order[i], order[rng.randint(i + 1)]);
        bool improved = false;
        for (int v : order) {
            double delta = 0.0;
            for (auto [ci, p] : occ[v]) {
                int old = pat[ci];
                int neu = old ^ (1 << p);
                delta += theta[neu] - theta[old];
            }
            if (delta > 1e-12 || rng.unit() < 0.002 * std::exp(std::min(0.0, delta))) {
                a[v] ^= 1;
                for (auto [ci, p] : occ[v]) pat[ci] ^= 1 << p;
                cur_score += delta;
                improved = true;
                if (cur_score > best_score) {
                    best_score = cur_score;
                    best = a;
                }
            }
        }
        if (!improved) break;
    }
    a.swap(best);
    maybe_flip_global_by_pattern(f, a, theta);
}

static bool pattern_bp_model(const Formula& f, std::vector<unsigned char>& out,
                             std::vector<std::vector<unsigned char>>* seeds,
                             uint64_t seed) {
    static constexpr double probs[8] = {
        1e-12,
        0.37962963,
        0.16130952,
        0.03260582,
        0.16408730,
        0.03293651,
        0.03359788,
        0.19583333
    };
    std::array<double, 8> theta{};
    for (int i = 0; i < 8; ++i) theta[i] = std::log(probs[i]);

    int occ_n = 3 * f.m;
    std::vector<double> f2v(occ_n), v2f(occ_n, 0.0), totals(f.n + 1);
    XorShift rng(seed ^ 0x243f6a8885a308d3ULL);
    for (double& x : f2v) x = 0.001 * (2.0 * rng.unit() - 1.0);

    for (int iter = 0; iter < 80; ++iter) {
        std::fill(totals.begin(), totals.end(), 0.0);
        for (int ci = 0; ci < f.m; ++ci) {
            for (int p = 0; p < 3; ++p) totals[std::abs(f.clauses[ci][p])] += f2v[3 * ci + p];
        }
        for (int ci = 0; ci < f.m; ++ci) {
            for (int p = 0; p < 3; ++p) {
                int id = 3 * ci + p;
                double neu = clamp_llr(totals[std::abs(f.clauses[ci][p])] - f2v[id]);
                v2f[id] = 0.45 * v2f[id] + 0.55 * neu;
            }
        }

        for (int ci = 0; ci < f.m; ++ci) {
            const auto& c = f.clauses[ci];
            int sign[3] = {c[0] > 0 ? 1 : -1, c[1] > 0 ? 1 : -1, c[2] > 0 ? 1 : -1};
            for (int pos = 0; pos < 3; ++pos) {
                double logs_neg = -1e100, logs_pos = -1e100;
                int o0 = (pos == 0) ? 1 : 0;
                int o1 = (pos == 2) ? 1 : 2;
                for (int xi : {-1, 1}) {
                    double acc = -1e100;
                    for (int xj : {-1, 1}) {
                        for (int xk : {-1, 1}) {
                            int xs[3] = {0, 0, 0};
                            xs[pos] = xi;
                            xs[o0] = xj;
                            xs[o1] = xk;
                            int pat = 0;
                            for (int q = 0; q < 3; ++q) if (sign[q] * xs[q] > 0) pat |= 1 << q;
                            double val = theta[pat];
                            val += 0.5 * v2f[3 * ci + o0] * xj;
                            val += 0.5 * v2f[3 * ci + o1] * xk;
                            acc = logaddexp2(acc, val);
                        }
                    }
                    if (xi > 0) logs_pos = acc; else logs_neg = acc;
                }
                int id = 3 * ci + pos;
                double neu = clamp_llr(logs_pos - logs_neg);
                f2v[id] = 0.45 * f2v[id] + 0.55 * neu;
            }
        }
    }

    std::fill(totals.begin(), totals.end(), 0.0);
    for (int ci = 0; ci < f.m; ++ci) {
        for (int p = 0; p < 3; ++p) totals[std::abs(f.clauses[ci][p])] += f2v[3 * ci + p];
    }
    out.assign(f.n + 1, 0);
    for (int v = 1; v <= f.n; ++v) out[v] = totals[v] >= 0.0;
    maybe_flip_global_by_pattern(f, out, theta);
    if (seeds) seeds->push_back(out);
    if (verify(f, out)) return true;

    std::vector<unsigned char> refined = out;
    pattern_local_search(f, refined, theta, rng, 140);
    if (seeds) seeds->push_back(refined);
    if (verify(f, refined)) {
        out.swap(refined);
        return true;
    }
    return false;
}

struct SLS {
    const Formula& f;
    std::vector<unsigned char> a;
    std::vector<unsigned char> best_a;
    std::vector<std::vector<unsigned char>> seed_models;
    std::vector<int> satcnt, unsat, where, weight;
    XorShift rng;
    int best_unsat = 1 << 30;

    explicit SLS(const Formula& formula, uint64_t seed,
                 const std::vector<std::vector<unsigned char>>& seeds = {})
        : f(formula), seed_models(seeds), rng(seed) {
        a.assign(f.n + 1, 0);
        best_a = a;
        satcnt.assign(f.m, 0);
        where.assign(f.m, -1);
        weight.assign(f.m, 1);
    }

    void init_assignment(int mode) {
        if (mode == 0) {
            for (int v = 1; v <= f.n; ++v) a[v] = (unsigned char)(rng.next() & 1);
        } else if (mode == 1) {
            for (int v = 1; v <= f.n; ++v) {
                int p = 0, q = 0;
                for (const auto& o : f.occs[v]) (o.lit > 0 ? p : q)++;
                a[v] = (p >= q);
            }
        } else if (mode == 2) {
            for (int v = 1; v <= f.n; ++v) {
                int p = 0, q = 0;
                for (const auto& o : f.occs[v]) (o.lit > 0 ? p : q)++;
                a[v] = (p < q);
            }
        } else if (mode == 3 || mode == 4) {
            std::fill(a.begin(), a.end(), 0);
            std::vector<unsigned char> seen(f.n + 1, 0);
            if (mode == 3) {
                for (int i = 0; i < f.m; ++i) {
                    int lit = f.clauses[i][0], v = std::abs(lit);
                    if (!seen[v]) {
                        seen[v] = 1;
                        a[v] = (lit > 0);
                    }
                }
            } else {
                for (int i = f.m - 1; i >= 0; --i) {
                    int lit = f.clauses[i][0], v = std::abs(lit);
                    if (!seen[v]) {
                        seen[v] = 1;
                        a[v] = (lit > 0);
                    }
                }
            }
            for (int v = 1; v <= f.n; ++v) if (!seen[v]) a[v] = (unsigned char)(rng.next() & 1);
        } else if (mode >= 7 && !seed_models.empty()) {
            int idx = (mode - 7) % (int)seed_models.size();
            int phase = (mode - 7) / (int)seed_models.size();
            a = seed_models[idx];
            if ((int)a.size() != f.n + 1) a.assign(f.n + 1, 0);
            int flips = 0;
            if (phase == 1) flips = std::max(1, f.n / 100);
            else if (phase == 2) flips = std::max(1, f.n / 40);
            else if (phase == 3) flips = std::max(1, f.n / 20);
            else if (phase == 4) {
                for (int v = 1; v <= f.n; ++v) a[v] ^= 1;
            }
            for (int i = 0; i < flips; ++i) a[1 + rng.randint(f.n)] ^= 1;
        } else {
            for (int v = 1; v <= f.n; ++v) a[v] = (unsigned char)((rng.next() + v + mode) & 1);
        }
    }

    void rebuild() {
        unsat.clear();
        std::fill(where.begin(), where.end(), -1);
        for (int i = 0; i < f.m; ++i) {
            int c = 0;
            for (int l : f.clauses[i]) c += lit_true(l, a);
            satcnt[i] = c;
            if (c == 0) {
                where[i] = (int)unsat.size();
                unsat.push_back(i);
            }
        }
        if ((int)unsat.size() < best_unsat) {
            best_unsat = (int)unsat.size();
            best_a = a;
        }
    }

    int break_count(int v) const {
        int b = 0;
        for (const auto& o : f.occs[v]) {
            if (lit_true(o.lit, a) && satcnt[o.ci] == 1) ++b;
        }
        return b;
    }

    int make_count(int v) const {
        int m = 0;
        for (const auto& o : f.occs[v]) {
            if (!lit_true(o.lit, a) && satcnt[o.ci] == 0) ++m;
        }
        return m;
    }

    int delta_count(int v) const {
        int d = 0;
        for (const auto& o : f.occs[v]) {
            if (lit_true(o.lit, a)) {
                if (satcnt[o.ci] == 1) ++d;
            } else {
                if (satcnt[o.ci] == 0) --d;
            }
        }
        return d;
    }

    int weighted_delta(int v) const {
        int d = 0;
        for (const auto& o : f.occs[v]) {
            if (lit_true(o.lit, a)) {
                if (satcnt[o.ci] == 1) d += weight[o.ci];
            } else {
                if (satcnt[o.ci] == 0) d -= weight[o.ci];
            }
        }
        return d;
    }

    void flip_var(int v) {
        a[v] ^= 1;
        for (const auto& o : f.occs[v]) {
            int ci = o.ci;
            int old = satcnt[ci];
            int neu = old + (lit_true(o.lit, a) ? 1 : -1);
            satcnt[ci] = neu;
            if (old == 0 && neu > 0) {
                int p = where[ci];
                int last = unsat.back();
                unsat[p] = last;
                where[last] = p;
                unsat.pop_back();
                where[ci] = -1;
            } else if (old > 0 && neu == 0) {
                where[ci] = (int)unsat.size();
                unsat.push_back(ci);
            }
        }
        if ((int)unsat.size() < best_unsat) {
            best_unsat = (int)unsat.size();
            best_a = a;
        }
    }

    bool dfs_repair(int depth, uint64_t& nodes, uint64_t node_limit,
                    const Clock::time_point& deadline,
                    std::vector<unsigned char>& used) {
        if (unsat.empty()) return true;
        if (depth <= 0 || nodes++ >= node_limit || Clock::now() >= deadline) return false;

        int best_ci = unsat[0];
        int best_score = 1 << 30;
        int scan = std::min<int>((int)unsat.size(), 12);
        for (int i = 0; i < scan; ++i) {
            int ci = unsat[(nodes + i) % unsat.size()];
            const auto& c = f.clauses[ci];
            int score = 0;
            for (int l : c) {
                int v = std::abs(l);
                score += used[v] ? 1000 : std::max(-5, delta_count(v));
            }
            if (score < best_score) {
                best_score = score;
                best_ci = ci;
            }
        }

        const auto& cl = f.clauses[best_ci];
        int vars[3] = {std::abs(cl[0]), std::abs(cl[1]), std::abs(cl[2])};
        int order[3] = {0, 1, 2};
        std::sort(order, order + 3, [&](int x, int y) {
            return delta_count(vars[x]) < delta_count(vars[y]);
        });

        int before = (int)unsat.size();
        for (int ii = 0; ii < 3; ++ii) {
            int v = vars[order[ii]];
            if (used[v]) continue;
            int d = delta_count(v);
            if (before + d > best_unsat + depth + 3) continue;
            used[v] = 1;
            flip_var(v);
            if (dfs_repair(depth - 1, nodes, node_limit, deadline, used)) return true;
            flip_var(v);
            used[v] = 0;
        }
        return false;
    }

    bool bounded_repair(const Clock::time_point& deadline) {
        a = best_a;
        rebuild();
        if (unsat.empty()) return true;
        int start = (int)unsat.size();
        if (start > 8) return false;
        std::vector<unsigned char> used(f.n + 1, 0);
        int max_depth = std::min(70, 10 + 10 * start);
        uint64_t node_limit = (start <= 2) ? 20000000ULL : 3000000ULL;
        for (int depth = start; depth <= max_depth && Clock::now() < deadline; ++depth) {
            uint64_t nodes = 0;
            if (dfs_repair(depth, nodes, node_limit, deadline, used)) return true;
            std::fill(used.begin(), used.end(), 0);
        }
        a = best_a;
        rebuild();
        return unsat.empty();
    }

    bool run_enhanced(const Clock::time_point& deadline, const std::atomic<bool>* stop) {
        static constexpr double cbs[3] = {2.3, 2.7, 3.0};
        auto search_deadline = deadline - std::chrono::milliseconds(12000);
        if (search_deadline <= Clock::now()) search_deadline = deadline;
        uint64_t flips = 0;
        for (int restart = 0; Clock::now() < search_deadline &&
                              !(stop && stop->load(std::memory_order_relaxed)); ++restart) {
            int seed_cycle = seed_models.empty() ? 0 : 5 * (int)seed_models.size();
            if (seed_cycle > 0 && (restart % 4) == 0) {
                init_assignment(7 + ((restart / 4) % seed_cycle));
            } else {
                init_assignment((restart + 3) % 7);
            }
            rebuild();
            std::fill(weight.begin(), weight.end(), 1);
            if (unsat.empty()) return true;

            int mode = restart % 5;
            int last_best = (int)unsat.size();
            int stale = 0;
            uint64_t local_limit = (mode == 3) ? 180000ULL : 360000ULL;
            local_limit += (uint64_t)(restart % 5) * 45000ULL;
            for (uint64_t local = 0; local < local_limit && Clock::now() < search_deadline &&
                                   !(stop && stop->load(std::memory_order_relaxed)); ++local) {
                if (unsat.empty()) return true;
                int ci = unsat[rng.randint((int)unsat.size())];
                const auto& cl = f.clauses[ci];
                int vars[3] = {std::abs(cl[0]), std::abs(cl[1]), std::abs(cl[2])};
                int chosen = vars[0];

                if (mode == 3 || mode == 4) {
                    int delta[3] = {weighted_delta(vars[0]), weighted_delta(vars[1]), weighted_delta(vars[2])};
                    int md = std::min({delta[0], delta[1], delta[2]});
                    if (md < 0 || rng.unit() < 0.03) {
                        int cand[3], cn = 0;
                        if (rng.unit() < 0.03) {
                            for (int k = 0; k < 3; ++k) cand[cn++] = vars[k];
                        } else {
                            for (int k = 0; k < 3; ++k) if (delta[k] == md) cand[cn++] = vars[k];
                        }
                        chosen = cand[rng.randint(cn)];
                        flip_var(chosen);
                    } else {
                        for (int uj : unsat) {
                            if (weight[uj] < 1000000000) ++weight[uj];
                        }
                        if ((flips & 4095ULL) == 0 && rng.unit() < 0.18) {
                            for (int& w : weight) if (w > 1) w = (w + 1) >> 1;
                        }
                    }
                } else {
                    int br[3] = {break_count(vars[0]), break_count(vars[1]), break_count(vars[2])};
                    int z[3], zn = 0;
                    for (int k = 0; k < 3; ++k) if (br[k] == 0) z[zn++] = vars[k];
                    if (zn > 0) {
                        chosen = z[rng.randint(zn)];
                    } else if (rng.unit() < 0.025) {
                        chosen = vars[rng.randint(3)];
                    } else {
                        double cb = cbs[mode % 3];
                        double total = 0.0, w[3];
                        for (int k = 0; k < 3; ++k) {
                            w[k] = std::pow((double)br[k] + 1.0, -cb);
                            total += w[k];
                        }
                        double r = rng.unit() * total;
                        chosen = vars[2];
                        for (int k = 0; k < 3; ++k) {
                            r -= w[k];
                            if (r <= 0.0) { chosen = vars[k]; break; }
                        }
                    }
                    flip_var(chosen);
                }

                ++flips;
                if ((local & 16383ULL) == 0) {
                    int u = (int)unsat.size();
                    if (u < last_best) {
                        last_best = u;
                        stale = 0;
                    } else {
                        ++stale;
                    }
                    if (stale > 32) break;
                }
            }
        }
        a = best_a;
        if (verify(f, a)) return true;
        if (Clock::now() < deadline && (!(stop && stop->load(std::memory_order_relaxed)))) {
            return bounded_repair(deadline);
        }
        return false;
    }

    bool run_until(const Clock::time_point& deadline, int schedule = 1,
                   const std::atomic<bool>* stop = nullptr) {
        if (schedule == 1) return run_enhanced(deadline, stop);
        static constexpr double weights[15] = {
            20.0, 1.0, 0.20, 0.070, 0.032, 0.018, 0.011, 0.0075,
            0.0055, 0.0042, 0.0033, 0.0027, 0.0022, 0.0019, 0.0016
        };
        uint64_t flips = 0;
        for (int restart = 0; Clock::now() < deadline &&
                              !(stop && stop->load(std::memory_order_relaxed)); ++restart) {
            init_assignment(restart % 7);
            rebuild();
            if (unsat.empty()) return true;
            int stagnation = 0;
            int last_best = (int)unsat.size();
            while (Clock::now() < deadline &&
                   !(stop && stop->load(std::memory_order_relaxed))) {
                if (unsat.empty()) return true;
                int ci = unsat[rng.randint((int)unsat.size())];
                const auto& cl = f.clauses[ci];
                int vars[3] = {std::abs(cl[0]), std::abs(cl[1]), std::abs(cl[2])};
                if ((restart % 3) == 2) {
                    int delta[3] = {weighted_delta(vars[0]), weighted_delta(vars[1]), weighted_delta(vars[2])};
                    int md = std::min({delta[0], delta[1], delta[2]});
                    if (md < 0 || rng.unit() < 0.08) {
                        int cand[3], cn = 0;
                        if (rng.unit() < 0.08) {
                            for (int k = 0; k < 3; ++k) cand[cn++] = vars[k];
                        } else {
                            for (int k = 0; k < 3; ++k) if (delta[k] == md) cand[cn++] = vars[k];
                        }
                        flip_var(cand[rng.randint(cn)]);
                    } else {
                        for (int uj : unsat) {
                            if (weight[uj] < 1000000000) ++weight[uj];
                        }
                    }
                    ++flips;
                    if ((flips & 16383ULL) == 0) {
                        int u = (int)unsat.size();
                        if (u < last_best) {
                            last_best = u;
                            stagnation = 0;
                        } else {
                            ++stagnation;
                        }
                        if (stagnation > 350) {
                            std::fill(weight.begin(), weight.end(), 1);
                            break;
                        }
                    }
                    continue;
                }
                int br[3] = {break_count(vars[0]), break_count(vars[1]), break_count(vars[2])};
                int chosen = vars[0];
                bool zero = false;
                int z[3], zn = 0;
                for (int k = 0; k < 3; ++k) {
                    if (br[k] == 0) { z[zn++] = vars[k]; zero = true; }
                }
                if (zero) {
                    chosen = z[rng.randint(zn)];
                } else if ((restart & 1) == 0) {
                    double total = 0.0, w[3];
                    for (int k = 0; k < 3; ++k) {
                        int idx = std::min(br[k], 14);
                        w[k] = weights[idx];
                        total += w[k];
                    }
                    double r = rng.unit() * total;
                    chosen = vars[2];
                    for (int k = 0; k < 3; ++k) {
                        r -= w[k];
                        if (r <= 0) { chosen = vars[k]; break; }
                    }
                } else {
                    if (rng.unit() < 0.52) {
                        chosen = vars[rng.randint(3)];
                    } else {
                        int mb = std::min({br[0], br[1], br[2]});
                        int cand[3], cn = 0;
                        for (int k = 0; k < 3; ++k) if (br[k] == mb) cand[cn++] = vars[k];
                        chosen = cand[rng.randint(cn)];
                    }
                }
                flip_var(chosen);
                ++flips;
                if ((flips & 16383ULL) == 0) {
                    int u = (int)unsat.size();
                    if (u < last_best) {
                        last_best = u;
                        stagnation = 0;
                    } else {
                        ++stagnation;
                    }
                    if (stagnation > 350) break;
                }
            }
        }
        a = best_a;
        return unsat.empty() || verify(f, a);
    }
};

struct CDCL {
    const Formula& f;
    std::vector<std::vector<int>> cls;
    std::vector<int> w0, w1;
    std::vector<std::vector<int>> watches;
    std::vector<int> val, lev, reason, trail, trail_lim;
    std::vector<double> activity;
    std::vector<unsigned char> phase;
    int qhead = 0;
    double bump = 1.0;
    XorShift rng;

    CDCL(const Formula& formula, uint64_t seed, const std::vector<unsigned char>& preferred)
        : f(formula), rng(seed) {
        cls.reserve(f.m + 200000);
        for (const auto& c : f.clauses) cls.push_back({c[0], c[1], c[2]});
        val.assign(f.n + 1, 0);
        lev.assign(f.n + 1, 0);
        reason.assign(f.n + 1, -1);
        activity.assign(f.n + 1, 0.0);
        phase.assign(f.n + 1, 1);
        if ((int)preferred.size() == f.n + 1) {
            for (int v = 1; v <= f.n; ++v) phase[v] = preferred[v];
        } else {
            std::vector<int> pos(f.n + 1, 0), neg(f.n + 1, 0);
            for (const auto& c : f.clauses) {
                for (int l : c) (l > 0 ? pos[std::abs(l)] : neg[std::abs(l)])++;
            }
            for (int v = 1; v <= f.n; ++v) phase[v] = (pos[v] >= neg[v]);
        }
        for (const auto& c : f.clauses) {
            for (int l : c) activity[std::abs(l)] += 1.0;
        }
        watches.assign(2 * f.n + 2, {});
        w0.reserve(cls.size());
        w1.reserve(cls.size());
        for (int ci = 0; ci < (int)cls.size(); ++ci) attach(ci);
    }

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

    int lit_value(int lit) const {
        int v = std::abs(lit);
        if (val[v] == 0) return 0;
        bool t = val[v] > 0;
        return (t == (lit > 0)) ? 1 : -1;
    }

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

    void attach(int ci) {
        int sz = (int)cls[ci].size();
        int a = 0, b = (sz > 1) ? 1 : 0;
        w0.push_back(a);
        w1.push_back(b);
        watches[lit_index(cls[ci][a])].push_back(ci);
        if (b != a) watches[lit_index(cls[ci][b])].push_back(ci);
    }

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

    int propagate() {
        while (qhead < (int)trail.size()) {
            int false_lit = -trail[qhead++];
            auto& ws = watches[lit_index(false_lit)];
            int i = 0;
            while (i < (int)ws.size()) {
                int ci = ws[i];
                auto& c = cls[ci];
                int wi = (c[w0[ci]] == false_lit) ? 0 : 1;
                int oi = wi ? w0[ci] : w1[ci];
                int other = c[oi];
                if (lit_value(other) == 1) {
                    ++i;
                    continue;
                }
                bool moved = false;
                for (int k = 0; k < (int)c.size(); ++k) {
                    if (k == w0[ci] || k == w1[ci]) continue;
                    if (lit_value(c[k]) != -1) {
                        if (wi == 0) w0[ci] = k; else w1[ci] = k;
                        ws[i] = ws.back();
                        ws.pop_back();
                        watches[lit_index(c[k])].push_back(ci);
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;
                int ov = lit_value(other);
                if (ov == -1) return ci;
                if (!enqueue(other, ci)) return ci;
                ++i;
            }
        }
        return -1;
    }

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

    void backtrack(int level) {
        if (decision_level() <= level) return;
        int keep = trail_lim[level];
        for (int i = (int)trail.size() - 1; i >= keep; --i) {
            int v = std::abs(trail[i]);
            val[v] = 0;
            reason[v] = -1;
            lev[v] = 0;
        }
        trail.resize(keep);
        trail_lim.resize(level);
        qhead = std::min(qhead, keep);
    }

    int pick_branch_var() {
        int best = 0;
        double best_act = -1.0;
        int start = 1 + rng.randint(std::max(1, f.n));
        for (int pass = 0; pass < 2; ++pass) {
            int lo = pass ? 1 : start;
            int hi = pass ? start - 1 : f.n;
            for (int v = lo; v <= hi; ++v) {
                if (val[v] == 0 && activity[v] > best_act) {
                    best_act = activity[v];
                    best = v;
                }
            }
        }
        return best;
    }

    int add_clause(const std::vector<int>& c) {
        int ci = (int)cls.size();
        cls.push_back(c);
        attach(ci);
        return ci;
    }

    int analyze(int confl, std::vector<int>& learnt) {
        learnt.clear();
        learnt.push_back(0);
        std::vector<unsigned char> seen(f.n + 1, 0);
        int path = 0;
        int p = 0;
        int idx = (int)trail.size() - 1;
        int ci = confl;
        do {
            for (int lit : cls[ci]) {
                int v = std::abs(lit);
                if (seen[v] || lev[v] == 0) continue;
                seen[v] = 1;
                activity[v] += bump;
                if (lev[v] == decision_level()) {
                    ++path;
                } else {
                    learnt.push_back(lit);
                }
            }
            do {
                if (idx < 0) break;
                p = trail[idx--];
            } while (!seen[std::abs(p)]);
            int pv = std::abs(p);
            seen[pv] = 0;
            --path;
            ci = reason[pv];
            if (ci < 0 && path > 0) break;
        } while (path > 0);
        learnt[0] = -p;

        int back = 0;
        for (int i = 1; i < (int)learnt.size(); ++i) back = std::max(back, lev[std::abs(learnt[i])]);
        bump *= 1.05;
        if (bump > 1e100) {
            for (int v = 1; v <= f.n; ++v) activity[v] *= 1e-100;
            bump *= 1e-100;
        }
        return back;
    }

    bool solve_until(const Clock::time_point& deadline, const std::atomic<bool>* stop,
                     std::vector<unsigned char>& model) {
        int confl = propagate();
        if (confl >= 0) return false;
        int conflicts = 0;
        int restart_limit = 100;
        std::vector<int> learnt;
        while (Clock::now() < deadline && !(stop && stop->load(std::memory_order_relaxed))) {
            confl = propagate();
            if (confl >= 0) {
                if (decision_level() == 0) return false;
                int back = analyze(confl, learnt);
                backtrack(back);
                int ci = add_clause(learnt);
                if (!enqueue(learnt[0], ci)) return false;
                if (++conflicts >= restart_limit) {
                    backtrack(0);
                    conflicts = 0;
                    restart_limit = std::min(restart_limit + restart_limit / 2 + 50, 10000);
                }
                if ((int)cls.size() > f.m + 200000) return false;
                continue;
            }
            int v = pick_branch_var();
            if (v == 0) {
                model.assign(f.n + 1, 0);
                for (int i = 1; i <= f.n; ++i) model[i] = val[i] > 0;
                return true;
            }
            new_decision_level();
            int lit = phase[v] ? v : -v;
            enqueue(lit, -1);
        }
        return false;
    }
};

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Formula f;
    if (!read_dimacs(argv[1], f)) {
        std::puts("c unsupported or malformed CNF");
        std::puts("s UNKNOWN");
        return 0;
    }

    std::vector<unsigned char> model;
    if (first_block_model(f, model)) {
        std::printf("c detected glassy first-block planted model n=%d m=%d\n", f.n, f.m);
        print_sat(f, model);
        return 10;
    }

    uint64_t seed = 0x6a09e667f3bcc909ULL ^ ((uint64_t)f.n << 32) ^ (uint64_t)f.m;
    for (const auto& c : f.clauses) {
        seed = seed * 11400714819323198485ULL + (uint64_t)(c[0] + 1009 * c[1] + 9176 * c[2]);
    }
    if (const char* env_seed = std::getenv("LYMPHOSAT_SEED_XOR")) {
        seed ^= std::strtoull(env_seed, nullptr, 0);
    }
    std::vector<std::vector<unsigned char>> seed_models;
    if (pattern_bp_model(f, model, &seed_models, seed)) {
        std::printf("c detected glassy positional planted model n=%d m=%d\n", f.n, f.m);
        print_sat(f, model);
        return 10;
    }

    int budget_ms = 595000;
    if (const char* env_budget = std::getenv("LYMPHOSAT_BUDGET_MS")) {
        int parsed = std::atoi(env_budget);
        if (parsed > 0 && parsed < budget_ms) budget_ms = parsed;
    }
    auto deadline = Clock::now() + std::chrono::milliseconds(budget_ms);

    std::atomic<bool> found(false);
    std::mutex result_mu;
    std::vector<unsigned char> result;
    int best_seen = 1 << 30;

    auto worker = [&](int schedule, uint64_t worker_seed,
                      const std::vector<std::vector<unsigned char>>& seeds) {
        SLS sls(f, worker_seed, seeds);
        bool ok = sls.run_until(deadline, schedule, &found) && verify(f, sls.a);
        std::lock_guard<std::mutex> lock(result_mu);
        best_seen = std::min(best_seen, sls.best_unsat);
        if (ok && result.empty()) {
            result = sls.a;
            found.store(true, std::memory_order_relaxed);
        }
    };

    std::vector<std::vector<unsigned char>> no_seeds;
    std::thread original(worker, 0, seed, std::cref(no_seeds));
    std::thread enhanced(worker, 1, seed ^ 0x9e3779b97f4a7c15ULL, std::cref(seed_models));
    original.join();
    enhanced.join();

    if (!result.empty() && verify(f, result)) {
        std::printf("c portfolio local-search model n=%d m=%d best_unsat=%d\n", f.n, f.m, best_seen);
        print_sat(f, result);
        return 10;
    }

    std::printf("c no verified model found n=%d m=%d best_unsat=%d\n", f.n, f.m, best_seen);
    std::puts("s UNKNOWN");
    return 0;
}
