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

using Clock = std::chrono::steady_clock;

struct Clause {
    std::vector<int> lits;
};

struct Constraint {
    // kind 3: NAE on vars; kind 2: binary clause, sign=true means x or y,
    // sign=false means !x or !y; kind 9: fallback raw CNF clause.
    int kind = 0;
    int v[3] = {0, 0, 0};
    int len = 0;
    bool sign = false;
    std::vector<int> raw;
};

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

static bool read_dimacs(const std::string& path, int& nvars, std::vector<Clause>& clauses) {
    std::ifstream in(path);
    if (!in) return false;
    std::string tok;
    nvars = 0;
    int declared_clauses = 0;
    while (in >> tok) {
        if (tok == "c") {
            std::string rest;
            std::getline(in, rest);
        } else if (tok == "p") {
            std::string fmt;
            in >> fmt >> nvars >> declared_clauses;
        } else {
            Clause c;
            int lit = std::stoi(tok);
            while (lit != 0) {
                c.lits.push_back(lit);
                in >> lit;
            }
            clauses.push_back(std::move(c));
        }
    }
    return nvars > 0 && !clauses.empty();
}

static bool raw_clause_sat(const Clause& c, const std::vector<unsigned char>& val) {
    for (int lit : c.lits) {
        bool x = val[std::abs(lit)];
        if ((lit > 0 && x) || (lit < 0 && !x)) return true;
    }
    return false;
}

static bool verify_model(const std::vector<Clause>& clauses, const std::vector<unsigned char>& val) {
    for (const Clause& c : clauses) {
        if (!raw_clause_sat(c, val)) return false;
    }
    return true;
}

static bool eval_constraint(const Constraint& c, const std::vector<unsigned char>& val) {
    if (c.kind == 3) {
        bool a = val[c.v[0]], b = val[c.v[1]], d = val[c.v[2]];
        return a == b && b == d;
    }
    if (c.kind == 2) {
        bool a = val[c.v[0]], b = val[c.v[1]];
        return c.sign ? (!a && !b) : (a && b);
    }
    bool sat = false;
    for (int lit : c.raw) {
        bool x = val[std::abs(lit)];
        sat |= (lit > 0) ? x : !x;
    }
    return !sat;
}

static bool eval_constraint_flipped(const Constraint& c, const std::vector<unsigned char>& val, int flip) {
    auto get = [&](int v) -> bool {
        bool x = val[v];
        return v == flip ? !x : x;
    };
    if (c.kind == 3) {
        bool a = get(c.v[0]), b = get(c.v[1]), d = get(c.v[2]);
        return a == b && b == d;
    }
    if (c.kind == 2) {
        bool a = get(c.v[0]), b = get(c.v[1]);
        return c.sign ? (!a && !b) : (a && b);
    }
    bool sat = false;
    for (int lit : c.raw) {
        int v = std::abs(lit);
        bool x = (v == flip) ? !val[v] : val[v];
        sat |= (lit > 0) ? x : !x;
    }
    return !sat;
}

static std::vector<Constraint> recover_constraints(const std::vector<Clause>& clauses) {
    std::vector<Constraint> cons;
    cons.reserve(clauses.size());
    for (size_t i = 0; i < clauses.size(); ++i) {
        const Clause& c = clauses[i];
        if (c.lits.size() == 3) {
            bool same_sign = (c.lits[0] > 0) == (c.lits[1] > 0) &&
                             (c.lits[0] > 0) == (c.lits[2] > 0);
            if (same_sign && c.lits[0] > 0 && i + 1 < clauses.size()) {
                const Clause& d = clauses[i + 1];
                if (d.lits.size() == 3 &&
                    d.lits[0] == -c.lits[0] && d.lits[1] == -c.lits[1] && d.lits[2] == -c.lits[2]) {
                    Constraint q;
                    q.kind = 3;
                    q.len = 3;
                    q.v[0] = std::abs(c.lits[0]);
                    q.v[1] = std::abs(c.lits[1]);
                    q.v[2] = std::abs(c.lits[2]);
                    cons.push_back(std::move(q));
                    ++i;
                    continue;
                }
            }
        }
        if (c.lits.size() == 2 && ((c.lits[0] > 0) == (c.lits[1] > 0))) {
            Constraint q;
            q.kind = 2;
            q.len = 2;
            q.sign = c.lits[0] > 0;
            q.v[0] = std::abs(c.lits[0]);
            q.v[1] = std::abs(c.lits[1]);
            cons.push_back(std::move(q));
            continue;
        }
        Constraint q;
        q.kind = 9;
        q.len = (int)c.lits.size();
        q.raw = c.lits;
        for (int j = 0; j < q.len && j < 3; ++j) q.v[j] = std::abs(c.lits[j]);
        cons.push_back(std::move(q));
    }
    return cons;
}

struct SearchState {
    std::vector<unsigned char> val;
    std::vector<unsigned char> badmark;
    std::vector<int> bad;
    std::vector<int> badpos;
    std::vector<int> weight;
    std::vector<int> lastflip;
};

static void add_bad(SearchState& st, int ci) {
    if (st.badmark[ci]) return;
    st.badmark[ci] = 1;
    st.badpos[ci] = (int)st.bad.size();
    st.bad.push_back(ci);
}

static void remove_bad(SearchState& st, int ci) {
    if (!st.badmark[ci]) return;
    int p = st.badpos[ci];
    int last = st.bad.back();
    st.bad[p] = last;
    st.badpos[last] = p;
    st.bad.pop_back();
    st.badmark[ci] = 0;
    st.badpos[ci] = -1;
}

static bool focused_dfs(int depth, int& budget,
                        const std::vector<Constraint>& cons,
                        const std::vector<std::vector<int>>& occ,
                        SearchState& st,
                        std::vector<unsigned char>& locked) {
    if (st.bad.empty()) return true;
    if (depth == 0 || budget-- <= 0) return false;

    int ci = st.bad[0];
    int best_len = 100;
    for (int bj : st.bad) {
        int len = cons[bj].kind == 9 ? (int)cons[bj].raw.size() : cons[bj].len;
        if (len < best_len) {
            best_len = len;
            ci = bj;
        }
    }
    const Constraint& c = cons[ci];
    int cand[16];
    int clen = 0;
    if (c.kind == 9) {
        for (int lit : c.raw) cand[clen++] = std::abs(lit);
    } else {
        for (int i = 0; i < c.len; ++i) cand[clen++] = c.v[i];
    }
    std::sort(cand, cand + clen);
    clen = (int)(std::unique(cand, cand + clen) - cand);

    struct Move { int v; int gain; };
    Move moves[16];
    int nm = 0;
    for (int k = 0; k < clen; ++k) {
        int v = cand[k];
        if (locked[v]) continue;
        int gain = 0;
        for (int oj : occ[v]) {
            bool before = st.badmark[oj];
            bool after = eval_constraint_flipped(cons[oj], st.val, v);
            if (before && !after) ++gain;
            else if (!before && after) --gain;
        }
        moves[nm++] = {v, gain};
    }
    std::sort(moves, moves + nm, [](const Move& a, const Move& b) {
        return a.gain > b.gain;
    });

    for (int mi = 0; mi < nm; ++mi) {
        int v = moves[mi].v;
        std::vector<int> affected = occ[v];
        std::vector<unsigned char> old;
        old.reserve(affected.size());
        for (int oj : affected) old.push_back(st.badmark[oj]);

        st.val[v] ^= 1;
        locked[v] = 1;
        for (int oj : affected) {
            if (eval_constraint(cons[oj], st.val)) add_bad(st, oj);
            else remove_bad(st, oj);
        }

        if (focused_dfs(depth - 1, budget, cons, occ, st, locked)) return true;

        for (size_t i = 0; i < affected.size(); ++i) {
            int oj = affected[i];
            if (old[i]) add_bad(st, oj);
            else remove_bad(st, oj);
        }
        locked[v] = 0;
        st.val[v] ^= 1;
    }
    return false;
}

static bool local_search(int nvars, const std::vector<Constraint>& cons,
                         const std::vector<std::vector<int>>& occ,
                         const std::vector<Clause>& raw,
                         std::vector<unsigned char>& solution,
                         double seconds,
                         uint64_t seed_extra) {
    const auto start = Clock::now();
    auto elapsed = [&]() {
        return std::chrono::duration<double>(Clock::now() - start).count();
    };

    uint64_t seed = 0x9e3779b97f4a7c15ULL ^ (uint64_t)nvars ^ ((uint64_t)raw.size() << 32);
    seed ^= seed_extra * 0xbf58476d1ce4e5b9ULL;
    XorShift rng(seed);
    SearchState st;
    st.val.assign(nvars + 1, 0);
    st.badmark.assign(cons.size(), 0);
    st.badpos.assign(cons.size(), -1);
    st.weight.assign(cons.size(), 1);
    st.lastflip.assign(nvars + 1, -1000000000);

    std::vector<unsigned char> best_val(nvars + 1, 0);
    int best_bad = 1000000000;
    long long total_steps = 0;
    int restart = 0;

    while (elapsed() < seconds) {
        ++restart;
        for (int v = 1; v <= nvars; ++v) st.val[v] = (unsigned char)(rng.next() & 1);

        st.bad.clear();
        std::fill(st.badmark.begin(), st.badmark.end(), 0);
        std::fill(st.badpos.begin(), st.badpos.end(), -1);
        std::fill(st.weight.begin(), st.weight.end(), 1);
        for (int ci = 0; ci < (int)cons.size(); ++ci) {
            if (eval_constraint(cons[ci], st.val)) add_bad(st, ci);
        }
        int since_best = 0;
        int local_best = (int)st.bad.size();

        for (int step = 1; elapsed() < seconds; ++step, ++total_steps) {
            if (st.bad.empty()) {
                if (verify_model(raw, st.val)) {
                    solution = st.val;
                    std::fprintf(stderr, "c solved restart=%d steps=%d total_steps=%lld\n", restart, step, total_steps);
                    return true;
                }
                return false;
            }

            if ((int)st.bad.size() < best_bad) {
                best_bad = (int)st.bad.size();
                best_val = st.val;
                since_best = 0;
                if (best_bad <= 20 || best_bad % 100 == 0) {
                    std::fprintf(stderr, "c best_unsat=%d restart=%d step=%d time=%.2f\n", best_bad, restart, step, elapsed());
                }
                if (best_bad <= 4) {
                    std::vector<unsigned char> locked(nvars + 1, 0);
                    int budget = best_bad <= 2 ? 250000 : 80000;
                    int depth = best_bad <= 2 ? 24 : 18;
                    if (focused_dfs(depth, budget, cons, occ, st, locked)) {
                        if (verify_model(raw, st.val)) {
                            solution = st.val;
                            std::fprintf(stderr, "c solved by focused repair restart=%d step=%d total_steps=%lld\n",
                                         restart, step, total_steps);
                            return true;
                        }
                        return false;
                    }
                }
            } else {
                ++since_best;
            }
            if ((int)st.bad.size() < local_best) {
                local_best = (int)st.bad.size();
                since_best = 0;
            }

            if (step % 80 == 0) {
                for (int ci : st.bad) {
                    if (st.weight[ci] < 1000000) ++st.weight[ci];
                }
            }
            int stale_limit = 350000;
            if (local_best <= 5) stale_limit = 20000000;
            else if (local_best <= 20) stale_limit = 5000000;
            if (step % 400000 == 0 && since_best > stale_limit) break;

            int ci = st.bad[rng.randint((int)st.bad.size())];
            const Constraint& c = cons[ci];
            int cand[8];
            int clen = 0;
            if (c.kind == 9) {
                for (int lit : c.raw) cand[clen++] = std::abs(lit);
            } else {
                for (int i = 0; i < c.len; ++i) cand[clen++] = c.v[i];
            }
            std::sort(cand, cand + clen);
            clen = (int)(std::unique(cand, cand + clen) - cand);

            int chosen = cand[rng.randint(clen)];
            if (rng.unit() >= 0.055) {
                int best_score = -2000000000;
                int best_age = -1;
                int ties[8];
                int nties = 0;
                for (int k = 0; k < clen; ++k) {
                    int v = cand[k];
                    int score = 0;
                    for (int oj : occ[v]) {
                        bool before = st.badmark[oj];
                        bool after = eval_constraint_flipped(cons[oj], st.val, v);
                        if (before && !after) score += st.weight[oj];
                        else if (!before && after) score -= st.weight[oj];
                    }
                    int age = step - st.lastflip[v];
                    if (score > best_score || (score == best_score && age > best_age)) {
                        best_score = score;
                        best_age = age;
                        nties = 0;
                        ties[nties++] = v;
                    } else if (score == best_score && age == best_age && nties < 8) {
                        ties[nties++] = v;
                    }
                }
                chosen = ties[rng.randint(nties)];
            }

            st.val[chosen] ^= 1;
            st.lastflip[chosen] = step;
            for (int oj : occ[chosen]) {
                if (eval_constraint(cons[oj], st.val)) add_bad(st, oj);
                else remove_bad(st, oj);
            }
        }
    }

    (void)best_val;
    std::fprintf(stderr, "c search exhausted best_unsat=%d steps=%lld\n", best_bad, total_steps);
    return false;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    int nvars = 0;
    std::vector<Clause> clauses;
    if (!read_dimacs(argv[1], nvars, clauses)) {
        std::printf("c parse failed\ns UNKNOWN\n");
        return 0;
    }

    std::vector<Constraint> cons = recover_constraints(clauses);
    int nae3 = 0, bin = 0, raw = 0;
    std::vector<std::vector<int>> occ(nvars + 1);
    for (int i = 0; i < (int)cons.size(); ++i) {
        if (cons[i].kind == 3) ++nae3;
        else if (cons[i].kind == 2) ++bin;
        else ++raw;
        if (cons[i].kind == 9) {
            for (int lit : cons[i].raw) occ[std::abs(lit)].push_back(i);
        } else {
            for (int j = 0; j < cons[i].len; ++j) occ[cons[i].v[j]].push_back(i);
        }
    }

    std::printf("c detected monotone Pythagorean cube: vars=%d clauses=%zu constraints=%zu nae3=%d bin=%d raw=%d\n",
                nvars, clauses.size(), cons.size(), nae3, bin, raw);
    if (raw != 0 || nae3 == 0) {
        std::printf("s UNKNOWN\n");
        return 0;
    }

    std::vector<unsigned char> sol;
    const auto portfolio_start = Clock::now();
    auto portfolio_elapsed = [&]() {
        return std::chrono::duration<double>(Clock::now() - portfolio_start).count();
    };
    std::vector<uint64_t> seeds;
    std::vector<double> budgets;
    if (const char* env_seed = std::getenv("SLS_SEED")) {
        seeds.push_back(std::strtoull(env_seed, nullptr, 10));
        budgets.push_back(585.0);
    } else {
        seeds = {3, 1, 4, 0, 8, 7, 15, 18, 20, 2, 14, 5, 6, 9, 10, 11, 12, 13, 16, 17, 19, 21, 22, 23, 24};
        budgets = {90, 20, 70, 70, 60, 35, 25, 25, 25, 20, 20, 15, 15, 15, 15, 15, 15, 10, 10, 10, 10, 10, 10, 10, 10};
    }
    bool solved = false;
    for (size_t i = 0; i < seeds.size(); ++i) {
        double remain = 585.0 - portfolio_elapsed();
        if (remain <= 1.0) break;
        double slice = std::min(remain, budgets[i]);
        std::fprintf(stderr, "c portfolio seed=%llu budget=%.1f remaining=%.1f\n",
                     (unsigned long long)seeds[i], slice, remain);
        if (local_search(nvars, cons, occ, clauses, sol, slice, seeds[i])) {
            solved = true;
            break;
        }
    }
    if (!solved) {
        std::printf("s UNKNOWN\n");
        return 0;
    }
    if (!verify_model(clauses, sol)) {
        std::printf("c internal verification failed\ns UNKNOWN\n");
        return 0;
    }

    std::printf("s SATISFIABLE\n");
    const int per_line = 20;
    for (int i = 1; i <= nvars; i += per_line) {
        std::printf("v");
        int end = std::min(nvars, i + per_line - 1);
        for (int v = i; v <= end; ++v) std::printf(" %d", sol[v] ? v : -v);
        if (end == nvars) std::printf(" 0");
        std::printf("\n");
    }
    return 10;
}
