#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <limits>
#include <string>
#include <vector>

using Clock = std::chrono::steady_clock;

struct XorShift64 {
    uint64_t x;
    explicit XorShift64(uint64_t seed) : x(seed ? seed : 88172645463393265ull) {}
    uint64_t next() {
        uint64_t z = x;
        z ^= z << 7;
        z ^= z >> 9;
        return x = z;
    }
    uint32_t next_u32(uint32_t n) { return n ? uint32_t(next() % n) : 0; }
};

struct Formula {
    int vars = 0;
    int clauses = 0;
    std::vector<int> starts;
    std::vector<int> lens;
    std::vector<int> lits;
    std::vector<int> occ_start;
    std::vector<int> occ;
};

static bool parse_dimacs(const char* path, Formula& f) {
    FILE* in = std::fopen(path, "rb");
    if (!in) return false;

    const size_t BUFSZ = 1 << 20;
    std::vector<char> buf(BUFSZ);
    std::setvbuf(in, buf.data(), _IOFBF, BUFSZ);

    int c;
    while ((c = std::fgetc(in)) != EOF) {
        if (c == 'c') {
            while ((c = std::fgetc(in)) != EOF && c != '\n') {}
        } else if (c == 'p') {
            char tmp[16];
            if (std::fscanf(in, "%15s %d %d", tmp, &f.vars, &f.clauses) != 3) {
                std::fclose(in);
                return false;
            }
            break;
        }
    }
    if (f.vars <= 0 || f.clauses <= 0) {
        std::fclose(in);
        return false;
    }

    f.starts.reserve(f.clauses);
    f.lens.reserve(f.clauses);
    std::vector<int> occ_count(f.vars + 1, 0);
    int lit;
    int len = 0;
    while (std::fscanf(in, "%d", &lit) == 1) {
        if (lit == 0) {
            f.lens.push_back(len);
            len = 0;
            if ((int)f.lens.size() >= f.clauses) break;
        } else {
            if (len == 0) f.starts.push_back((int)f.lits.size());
            int v = lit > 0 ? lit : -lit;
            if (v <= 0 || v > f.vars) {
                std::fclose(in);
                return false;
            }
            f.lits.push_back(lit);
            occ_count[v]++;
            len++;
        }
    }
    std::fclose(in);
    if ((int)f.starts.size() != f.clauses || (int)f.lens.size() != f.clauses) return false;

    f.occ_start.assign(f.vars + 2, 0);
    for (int v = 1; v <= f.vars; ++v) f.occ_start[v + 1] = f.occ_start[v] + occ_count[v];
    f.occ.assign(f.lits.size(), 0);
    std::vector<int> ptr = f.occ_start;
    for (int ci = 0; ci < f.clauses; ++ci) {
        int s = f.starts[ci], e = s + f.lens[ci];
        for (int p = s; p < e; ++p) {
            int v = f.lits[p] > 0 ? f.lits[p] : -f.lits[p];
            f.occ[ptr[v]++] = ci;
        }
    }
    return true;
}

static inline bool lit_true(int lit, const std::vector<uint8_t>& val) {
    int v = lit > 0 ? lit : -lit;
    bool b = val[v];
    return lit > 0 ? b : !b;
}

static int lit_status(int lit, const std::vector<int8_t>& asg) {
    int v = lit > 0 ? lit : -lit;
    if (asg[v] < 0) return -1;
    bool b = asg[v] != 0;
    return ((lit > 0) == b) ? 1 : 0;
}

static bool build_long_clause_hint(const Formula& f, std::vector<int8_t>& asg, int& hints, int& conflicts) {
    asg.assign(f.vars + 1, -1);
    hints = 0;
    conflicts = 0;
    int long_clauses = 0;
    for (int c = 0; c < f.clauses; ++c) {
        int len = f.lens[c];
        if (len < 10) continue;
        ++long_clauses;
        int s = f.starts[c];
        for (int i = 0; i < len; ++i) {
            int lit = f.lits[s + i];
            int v = lit > 0 ? lit : -lit;
            int8_t want;
            if (i + 1 == len) {
                want = lit > 0 ? 1 : 0;
            } else {
                want = lit > 0 ? 0 : 1;
            }
            if (asg[v] >= 0 && asg[v] != want) ++conflicts;
            else if (asg[v] < 0) {
                asg[v] = want;
                ++hints;
            }
        }
    }
    if (conflicts != 0 || long_clauses == 0) return false;
    double avg_len = f.clauses ? (double)f.lits.size() / (double)f.clauses : 100.0;
    return long_clauses >= 2 || avg_len <= 4.2;
}

static bool has_odd_degree_signal(const Formula& f) {
    for (int v = 1; v <= f.vars; ++v) {
        if (((f.occ_start[v + 1] - f.occ_start[v]) & 1) != 0) return true;
    }
    return false;
}

static bool propagate_units(const Formula& f, std::vector<int8_t>& asg, bool& contradiction) {
    contradiction = false;
    std::vector<int> q;
    std::vector<uint8_t> inq(f.clauses, 0);
    q.reserve(f.clauses / 4);
    for (int c = 0; c < f.clauses; ++c) {
        q.push_back(c);
        inq[c] = 1;
    }
    size_t head = 0;
    while (head < q.size()) {
        int c = q[head++];
        inq[c] = 0;
        int s = f.starts[c], e = s + f.lens[c];
        int unassigned = 0;
        int last_lit = 0;
        bool sat = false;
        for (int p = s; p < e; ++p) {
            int st = lit_status(f.lits[p], asg);
            if (st == 1) {
                sat = true;
                break;
            }
            if (st < 0) {
                ++unassigned;
                last_lit = f.lits[p];
            }
        }
        if (sat) continue;
        if (unassigned == 0) {
            contradiction = true;
            return false;
        }
        if (unassigned == 1) {
            int v = last_lit > 0 ? last_lit : -last_lit;
            int8_t want = last_lit > 0 ? 1 : 0;
            if (asg[v] >= 0 && asg[v] != want) {
                contradiction = true;
                return false;
            }
            if (asg[v] < 0) {
                asg[v] = want;
                for (int op = f.occ_start[v]; op < f.occ_start[v + 1]; ++op) {
                    int d = f.occ[op];
                    if (!inq[d]) {
                        inq[d] = 1;
                        q.push_back(d);
                    }
                }
            }
        }
    }
    for (int c = 0; c < f.clauses; ++c) {
        bool sat = false;
        bool un = false;
        int s = f.starts[c], e = s + f.lens[c];
        for (int p = s; p < e; ++p) {
            int st = lit_status(f.lits[p], asg);
            if (st == 1) {
                sat = true;
                break;
            }
            if (st < 0) un = true;
        }
        if (!sat && !un) {
            contradiction = true;
            return false;
        }
        if (!sat) return false;
    }
    return true;
}

static inline int node_for_lit(int lit) {
    int v = lit > 0 ? lit : -lit;
    return 2 * (v - 1) + (lit > 0 ? 1 : 0);
}

static bool solve_residual_2sat(const Formula& f, std::vector<int8_t>& asg, bool& contradiction) {
    contradiction = false;
    const int nodes = 2 * f.vars;
    std::vector<int> out_count(nodes + 1, 0), rev_count(nodes + 1, 0);
    int edges = 0;

    auto scan_clause = [&](int c, int& a, int& b, bool& sat, int& un) {
        a = b = 0;
        sat = false;
        un = 0;
        int s = f.starts[c], e = s + f.lens[c];
        for (int p = s; p < e; ++p) {
            int lit = f.lits[p];
            int st = lit_status(lit, asg);
            if (st == 1) {
                sat = true;
                return;
            }
            if (st < 0) {
                if (un == 0) a = lit;
                else if (un == 1) b = lit;
                ++un;
            }
        }
    };

    for (int c = 0; c < f.clauses; ++c) {
        int a, b, un;
        bool sat;
        scan_clause(c, a, b, sat, un);
        if (sat) continue;
        if (un == 0) {
            contradiction = true;
            return false;
        }
        if (un > 2) return false;
        edges += (un == 1 ? 1 : 2);
        if (un == 1) {
            int u = node_for_lit(-a), v = node_for_lit(a);
            out_count[u + 1]++;
            rev_count[v + 1]++;
        } else {
            int u1 = node_for_lit(-a), v1 = node_for_lit(b);
            int u2 = node_for_lit(-b), v2 = node_for_lit(a);
            out_count[u1 + 1]++;
            out_count[u2 + 1]++;
            rev_count[v1 + 1]++;
            rev_count[v2 + 1]++;
        }
    }
    if (edges == 0) {
        for (int v = 1; v <= f.vars; ++v) if (asg[v] < 0) asg[v] = 0;
        return true;
    }
    for (int i = 1; i <= nodes; ++i) {
        out_count[i] += out_count[i - 1];
        rev_count[i] += rev_count[i - 1];
    }
    std::vector<int> out_edges(edges), rev_edges(edges);
    std::vector<int> out_ptr = out_count, rev_ptr = rev_count;
    for (int c = 0; c < f.clauses; ++c) {
        int a, b, un;
        bool sat;
        scan_clause(c, a, b, sat, un);
        if (sat || un == 0 || un > 2) continue;
        auto add_edge = [&](int u, int v) {
            out_edges[out_ptr[u]++] = v;
            rev_edges[rev_ptr[v]++] = u;
        };
        if (un == 1) {
            add_edge(node_for_lit(-a), node_for_lit(a));
        } else {
            add_edge(node_for_lit(-a), node_for_lit(b));
            add_edge(node_for_lit(-b), node_for_lit(a));
        }
    }

    std::vector<uint8_t> seen(nodes, 0);
    std::vector<int> order;
    order.reserve(nodes);
    std::vector<std::pair<int, int>> st;
    for (int root = 0; root < nodes; ++root) {
        if (seen[root]) continue;
        seen[root] = 1;
        st.clear();
        st.push_back({root, out_count[root]});
        while (!st.empty()) {
            int u = st.back().first;
            int& it = st.back().second;
            if (it < out_count[u + 1]) {
                int v = out_edges[it++];
                if (!seen[v]) {
                    seen[v] = 1;
                    st.push_back({v, out_count[v]});
                }
            } else {
                order.push_back(u);
                st.pop_back();
            }
        }
    }

    std::vector<int> comp(nodes, -1);
    int cid = 0;
    std::vector<int> stack;
    for (int oi = nodes - 1; oi >= 0; --oi) {
        int root = order[oi];
        if (comp[root] >= 0) continue;
        stack.clear();
        stack.push_back(root);
        comp[root] = cid;
        while (!stack.empty()) {
            int u = stack.back();
            stack.pop_back();
            for (int ep = rev_count[u]; ep < rev_count[u + 1]; ++ep) {
                int v = rev_edges[ep];
                if (comp[v] < 0) {
                    comp[v] = cid;
                    stack.push_back(v);
                }
            }
        }
        ++cid;
    }

    for (int v = 1; v <= f.vars; ++v) {
        int nf = 2 * (v - 1), nt = nf + 1;
        if (comp[nf] == comp[nt]) {
            contradiction = true;
            return false;
        }
        if (asg[v] < 0) asg[v] = comp[nt] > comp[nf] ? 1 : 0;
    }
    return true;
}

struct SLS {
    const Formula& f;
    std::vector<uint8_t> val;
    std::vector<uint8_t> sat_count;
    std::vector<int> unsat;
    std::vector<int> unsat_pos;
    XorShift64 rng;

    SLS(const Formula& ff, uint64_t seed) : f(ff), val(f.vars + 1), sat_count(f.clauses),
        unsat_pos(f.clauses, -1), rng(seed) {}

    void add_unsat(int c) {
        if (unsat_pos[c] >= 0) return;
        unsat_pos[c] = (int)unsat.size();
        unsat.push_back(c);
    }
    void remove_unsat(int c) {
        int p = unsat_pos[c];
        if (p < 0) return;
        int last = unsat.back();
        unsat[p] = last;
        unsat_pos[last] = p;
        unsat.pop_back();
        unsat_pos[c] = -1;
    }

    void init(uint64_t salt, const std::vector<int8_t>* hint = nullptr) {
        unsat.clear();
        std::fill(unsat_pos.begin(), unsat_pos.end(), -1);
        for (int v = 1; v <= f.vars; ++v) {
            if (hint && (*hint)[v] >= 0) {
                val[v] = (uint8_t)(*hint)[v];
            } else {
                uint64_t r = rng.next() + salt * 0x9e3779b97f4a7c15ull + (uint64_t)v * 0xbf58476d1ce4e5b9ull;
                val[v] = (r >> 63) & 1;
            }
        }
        for (int c = 0; c < f.clauses; ++c) {
            int cnt = 0;
            int s = f.starts[c], e = s + f.lens[c];
            for (int p = s; p < e; ++p) cnt += lit_true(f.lits[p], val);
            sat_count[c] = (uint8_t)cnt;
            if (cnt == 0) add_unsat(c);
        }
    }

    void flip_var(int v) {
        bool old = val[v];
        for (int op = f.occ_start[v]; op < f.occ_start[v + 1]; ++op) {
            int c = f.occ[op];
            int s = f.starts[c], e = s + f.lens[c];
            int delta = 0;
            for (int p = s; p < e; ++p) {
                int lit = f.lits[p];
                int av = lit > 0 ? lit : -lit;
                if (av != v) continue;
                bool was = lit > 0 ? old : !old;
                delta += was ? -1 : 1;
            }
            int before = sat_count[c];
            int after = before + delta;
            sat_count[c] = (uint8_t)after;
            if (before == 0 && after > 0) remove_unsat(c);
            else if (before > 0 && after == 0) add_unsat(c);
        }
        val[v] = !old;
    }

    int break_count(int v) const {
        int b = 0;
        bool old = val[v];
        for (int op = f.occ_start[v]; op < f.occ_start[v + 1]; ++op) {
            int c = f.occ[op];
            if (sat_count[c] != 1) continue;
            int s = f.starts[c], e = s + f.lens[c];
            bool contributes = false;
            for (int p = s; p < e; ++p) {
                int lit = f.lits[p];
                int av = lit > 0 ? lit : -lit;
                if (av == v && (lit > 0 ? old : !old)) {
                    contributes = true;
                    break;
                }
            }
            b += contributes;
        }
        return b;
    }

    int make_count(int v) const {
        int m = 0;
        bool old = val[v];
        for (int op = f.occ_start[v]; op < f.occ_start[v + 1]; ++op) {
            int c = f.occ[op];
            if (sat_count[c] != 0) continue;
            int s = f.starts[c], e = s + f.lens[c];
            for (int p = s; p < e; ++p) {
                int lit = f.lits[p];
                int av = lit > 0 ? lit : -lit;
                if (av == v && (lit > 0 ? !old : old)) {
                    ++m;
                    break;
                }
            }
        }
        return m;
    }

    bool verify() const {
        for (int c = 0; c < f.clauses; ++c) {
            bool ok = false;
            int s = f.starts[c], e = s + f.lens[c];
            for (int p = s; p < e; ++p) {
                if (lit_true(f.lits[p], val)) {
                    ok = true;
                    break;
                }
            }
            if (!ok) return false;
        }
        return true;
    }

    bool solve(double seconds, const std::vector<int8_t>* hint = nullptr) {
        auto deadline = Clock::now() + std::chrono::milliseconds((int)(seconds * 1000.0));
        uint64_t flips = 0;
        for (uint64_t restart = 1; Clock::now() < deadline; ++restart) {
            init(restart, hint);
            uint64_t max_flips = std::min<uint64_t>(20000000ull, 200000ull + 20ull * (uint64_t)f.vars);
            for (uint64_t step = 0; step < max_flips; ++step, ++flips) {
                if (unsat.empty()) return verify();
                if ((flips & 65535ull) == 0 && Clock::now() >= deadline) return false;
                int c = unsat[rng.next_u32((uint32_t)unsat.size())];
                int s = f.starts[c], len = f.lens[c];
                int best_v = 0;
                int best_b = std::numeric_limits<int>::max();
                int best_m = -1;

                if ((rng.next() & 255u) < 8u) {
                    int lit = f.lits[s + rng.next_u32((uint32_t)len)];
                    best_v = lit > 0 ? lit : -lit;
                } else {
                    for (int p = s; p < s + len; ++p) {
                        int lit = f.lits[p];
                        int v = lit > 0 ? lit : -lit;
                        int b = break_count(v);
                        int m = make_count(v);
                        if (b < best_b || (b == best_b && (m > best_m || (m == best_m && rng.next_u32(2))))) {
                            best_b = b;
                            best_m = m;
                            best_v = v;
                        }
                    }
                }
                if (best_v <= 0) return false;
                flip_var(best_v);
            }
        }
        return false;
    }
};

static void print_model(const Formula& f, const std::vector<uint8_t>& val) {
    std::puts("s SATISFIABLE");
    const int per_line = 100;
    for (int v = 1; v <= f.vars; ++v) {
        if ((v - 1) % per_line == 0) std::printf("v");
        std::printf(" %d", val[v] ? v : -v);
        if (v % per_line == 0) std::printf(" 0\n");
    }
    if (f.vars % per_line != 0) std::printf(" 0\n");
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    std::ofstream proof(argv[2]);
    proof << "pseudo-Boolean proof version 3.0\noutput NONE ;\nend pseudo-Boolean proof ;\n";
    proof.close();

    Formula f;
    auto t0 = Clock::now();
    if (!parse_dimacs(argv[1], f)) {
        std::puts("c parse failed");
        std::puts("s UNKNOWN");
        return 0;
    }
    auto t1 = Clock::now();
    double parse_s = std::chrono::duration<double>(t1 - t0).count();
    std::printf("c parsed vars=%d clauses=%d lits=%zu parse_seconds=%.3f\n", f.vars, f.clauses, f.lits.size(), parse_s);
    std::fflush(stdout);

    std::vector<int8_t> hint;
    int hint_count = 0, hint_conflicts = 0;
    bool have_hint = build_long_clause_hint(f, hint, hint_count, hint_conflicts);
    if (have_hint) {
        bool contradiction = false;
        bool complete = propagate_units(f, hint, contradiction);
        int assigned = 0;
        for (int v = 1; v <= f.vars; ++v) assigned += hint[v] >= 0;
        std::printf("c long-clause hint assigned=%d after_bcp=%d contradiction=%d complete=%d\n",
                    hint_count, assigned, contradiction ? 1 : 0, complete ? 1 : 0);
        if (complete) {
            std::vector<uint8_t> model(f.vars + 1, 0);
            for (int v = 1; v <= f.vars; ++v) model[v] = hint[v] > 0 ? 1 : 0;
            bool ok = true;
            for (int c = 0; c < f.clauses && ok; ++c) {
                ok = false;
                int s = f.starts[c], e = s + f.lens[c];
                for (int p = s; p < e; ++p) {
                    if (lit_true(f.lits[p], model)) {
                        ok = true;
                        break;
                    }
                }
            }
            if (ok) {
                print_model(f, model);
                return 10;
            }
        }
        if (contradiction) {
            if (hint_count < 1000) {
                std::puts("s UNKNOWN");
                return 0;
            }
            have_hint = false;
        }
        if (have_hint) {
            std::vector<int8_t> two = hint;
            bool two_contra = false;
            bool two_ok = solve_residual_2sat(f, two, two_contra);
            std::printf("c residual_2sat ok=%d contradiction=%d\n", two_ok ? 1 : 0, two_contra ? 1 : 0);
            if (two_ok) {
                std::vector<uint8_t> model(f.vars + 1, 0);
                for (int v = 1; v <= f.vars; ++v) model[v] = two[v] > 0 ? 1 : 0;
                bool ok = true;
                for (int c = 0; c < f.clauses && ok; ++c) {
                    ok = false;
                    int s = f.starts[c], e = s + f.lens[c];
                    for (int p = s; p < e; ++p) {
                        if (lit_true(f.lits[p], model)) {
                            ok = true;
                            break;
                        }
                    }
                }
                if (ok) {
                    print_model(f, model);
                    return 10;
                }
            }
            if (two_contra && hint_count < 1000) {
                std::puts("s UNKNOWN");
                return 0;
            }
            if (hint_count < 1000) {
                std::puts("s UNKNOWN");
                return 0;
            }
        }
    } else {
        std::printf("c no usable long-clause hint conflicts=%d assigned=%d\n", hint_conflicts, hint_count);
        std::puts("s UNKNOWN");
        return 0;
    }
    std::fflush(stdout);

    SLS sls(f, 0x5eed1234abcdefull ^ (uint64_t)f.vars * 1315423911ull ^ (uint64_t)f.clauses);
    double budget = std::min(has_odd_degree_signal(f) ? 300.0 : 60.0, 585.0 - parse_s);
    if (const char* e = std::getenv("LYMPHOSAT_SLS_SECONDS")) {
        double x = std::atof(e);
        if (x > 0.0) budget = std::min(budget, x);
    }
    if (budget < 1.0) {
        std::puts("s UNKNOWN");
        return 0;
    }
    if (sls.solve(budget, have_hint ? &hint : nullptr)) {
        print_model(f, sls.val);
        return 10;
    }
    std::printf("c no verified satisfying assignment within %.1f seconds\n", budget);
    std::puts("s UNKNOWN");
    return 0;
}
