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

using namespace std;

struct Clause {
    vector<int> lits;
    int w0 = 0;
    int w1 = 0;
    bool learnt = false;
};

static chrono::steady_clock::time_point g_start;
static double elapsed_sec() {
    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();
}

struct Formula {
    int nvars = 0;
    vector<Clause> clauses;
    vector<vector<int>> occ;
    vector<char> majority;
    vector<int> maj_unsat_occ;
};

static bool parse_dimacs(const string &path, Formula &F) {
    ifstream in(path);
    if (!in) return false;
    string tok;
    int declared_m = 0;
    while (in >> tok) {
        if (tok == "c") {
            string rest;
            getline(in, rest);
        } else if (tok == "p") {
            string cnf;
            in >> cnf >> F.nvars >> declared_m;
            F.clauses.reserve(declared_m);
            break;
        }
    }
    if (F.nvars <= 0) return false;
    vector<int> lits;
    int x;
    while (in >> x) {
        if (x == 0) {
            if (!lits.empty()) {
                Clause c;
                c.lits = lits;
                c.w1 = (int)c.lits.size() > 1 ? 1 : 0;
                F.clauses.push_back(std::move(c));
                lits.clear();
            }
        } else {
            if (abs(x) > F.nvars) return false;
            lits.push_back(x);
        }
    }
    vector<int> pos(F.nvars + 1, 0), neg(F.nvars + 1, 0);
    F.occ.assign(F.nvars + 1, {});
    for (int ci = 0; ci < (int)F.clauses.size(); ++ci) {
        for (int l : F.clauses[ci].lits) {
            int v = abs(l);
            if (l > 0) pos[v]++; else neg[v]++;
            F.occ[v].push_back(ci);
        }
    }
    F.majority.assign(F.nvars + 1, 0);
    for (int v = 1; v <= F.nvars; ++v) {
        F.majority[v] = (neg[v] >= pos[v]) ? 1 : -1;
    }
    F.maj_unsat_occ.assign(F.nvars + 1, 0);
    for (const Clause &c : F.clauses) {
        bool sat = false;
        for (int l : c.lits) {
            int v = abs(l);
            if ((l > 0 && F.majority[v] == 1) || (l < 0 && F.majority[v] == -1)) {
                sat = true;
                break;
            }
        }
        if (!sat) {
            for (int l : c.lits) F.maj_unsat_occ[abs(l)]++;
        }
    }
    return true;
}

static bool verify_model(const Formula &F, const vector<char> &val) {
    for (const Clause &c : F.clauses) {
        bool sat = false;
        for (int l : c.lits) {
            int v = abs(l);
            if ((l > 0 && val[v] == 1) || (l < 0 && val[v] == -1)) {
                sat = true;
                break;
            }
        }
        if (!sat) return false;
    }
    return true;
}

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

struct LocalSearch {
    const Formula &F;
    vector<char> val;
    vector<int> satcnt, true_lit;
    vector<int> unsat, where_unsat;
    uint64_t rng = 0x9e3779b97f4a7c15ULL;

    explicit LocalSearch(const Formula &f) : F(f) {
        val.assign(F.nvars + 1, 0);
        satcnt.assign(F.clauses.size(), 0);
        true_lit.assign(F.clauses.size(), 0);
        where_unsat.assign(F.clauses.size(), -1);
    }

    uint32_t rnd() {
        rng ^= rng >> 12;
        rng ^= rng << 25;
        rng ^= rng >> 27;
        return (uint32_t)((rng * 2685821657736338717ULL) >> 32);
    }

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

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

    void init(int attempt) {
        unsat.clear();
        fill(where_unsat.begin(), where_unsat.end(), -1);
        for (int v = 1; v <= F.nvars; ++v) {
            val[v] = F.majority[v];
            if (attempt > 0 && (rnd() % 1000) < 20) val[v] = -val[v];
        }
        for (int ci = 0; ci < (int)F.clauses.size(); ++ci) {
            int cnt = 0, tl = 0;
            for (int l : F.clauses[ci].lits) {
                int v = abs(l);
                bool s = (l > 0 && val[v] == 1) || (l < 0 && val[v] == -1);
                if (s) {
                    cnt++;
                    tl = l;
                }
            }
            satcnt[ci] = cnt;
            true_lit[ci] = tl;
            if (cnt == 0) add_unsat(ci);
        }
    }

    int break_count(int v) {
        int b = 0;
        for (int ci : F.occ[v]) {
            if (satcnt[ci] == 1 && abs(true_lit[ci]) == v) b++;
        }
        return b;
    }

    void flip(int v) {
        char old = val[v];
        val[v] = -old;
        for (int ci : F.occ[v]) {
            Clause const &c = F.clauses[ci];
            int lit = 0;
            for (int l : c.lits) if (abs(l) == v) { lit = l; break; }
            bool was = (lit > 0 && old == 1) || (lit < 0 && old == -1);
            if (was) {
                satcnt[ci]--;
                if (satcnt[ci] == 0) {
                    true_lit[ci] = 0;
                    add_unsat(ci);
                } else if (true_lit[ci] == lit) {
                    int tl = 0;
                    for (int l : c.lits) {
                        int u = abs(l);
                        if ((l > 0 && val[u] == 1) || (l < 0 && val[u] == -1)) {
                            tl = l;
                            break;
                        }
                    }
                    true_lit[ci] = tl;
                }
            } else {
                if (satcnt[ci] == 0) remove_unsat(ci);
                satcnt[ci]++;
                true_lit[ci] = lit;
            }
        }
    }

    bool solve(double limit, vector<char> &out) {
        int attempts = 0;
        while (elapsed_sec() < limit) {
            init(attempts++);
            long long max_steps = 200000 + 200LL * F.nvars;
            for (long long step = 0; step < max_steps && elapsed_sec() < limit; ++step) {
                if (unsat.empty()) {
                    out = val;
                    return verify_model(F, out);
                }
                int ci = unsat[rnd() % unsat.size()];
                const Clause &c = F.clauses[ci];
                int bestv = abs(c.lits[rnd() % c.lits.size()]);
                int bestb = 1 << 30;
                if ((rnd() & 255) < 18) {
                    bestv = abs(c.lits[rnd() % c.lits.size()]);
                } else {
                    for (int l : c.lits) {
                        int v = abs(l);
                        int b = break_count(v);
                        if (b < bestb || (b == bestb && (rnd() & 1))) {
                            bestb = b;
                            bestv = v;
                        }
                    }
                }
                flip(bestv);
            }
        }
        return false;
    }
};

struct CDCL {
    Formula F;
    vector<vector<int>> watches;
    vector<char> assigns;
    vector<int> level, reason, trail, trail_lim;
    size_t qhead = 0;
    vector<double> activity;
    double var_inc = 1.0;
    ofstream proof;
    bool proof_open = false;

    explicit CDCL(const Formula &base) : F(base) {
        watches.assign(2 * F.nvars + 2, {});
        assigns.assign(F.nvars + 1, 0);
        level.assign(F.nvars + 1, 0);
        reason.assign(F.nvars + 1, -1);
        activity.assign(F.nvars + 1, 0.0);
        for (int ci = 0; ci < (int)F.clauses.size(); ++ci) {
            Clause &c = F.clauses[ci];
            if (c.lits.size() == 1) c.w1 = c.w0;
            watches[lit_index(c.lits[c.w0])].push_back(ci);
            if (c.w1 != c.w0) watches[lit_index(c.lits[c.w1])].push_back(ci);
            for (int l : c.lits) activity[abs(l)] += 1.0;
        }
        for (int v = 1; v <= F.nvars; ++v) {
            activity[v] += 50000.0 * F.maj_unsat_occ[v];
        }
    }

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

    int lit_value(int l) const {
        char a = assigns[abs(l)];
        if (a == 0) return 0;
        return (l > 0 ? a : -a) == 1 ? 1 : -1;
    }

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

    bool enqueue(int lit, int from) {
        int v = abs(lit);
        char val = lit > 0 ? 1 : -1;
        if (assigns[v] != 0) return assigns[v] == val;
        assigns[v] = val;
        level[v] = decision_level();
        reason[v] = from;
        trail.push_back(lit);
        return true;
    }

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

    void bump_clause(const vector<int> &cl) {
        for (int l : cl) activity[abs(l)] += var_inc;
        var_inc *= 1.05;
        if (var_inc > 1e100) {
            for (int v = 1; v <= F.nvars; ++v) activity[v] *= 1e-100;
            var_inc *= 1e-100;
        }
    }

    pair<vector<int>, int> analyze(int confl) {
        vector<char> seen(F.nvars + 1, 0);
        vector<int> learnt;
        int pathC = 0;
        int idx = (int)trail.size() - 1;
        int p = 0;
        const vector<int> *cl = &F.clauses[confl].lits;
        while (true) {
            for (int q : *cl) {
                int v = abs(q);
                if (v == abs(p)) continue;
                if (!seen[v] && level[v] > 0) {
                    seen[v] = 1;
                    activity[v] += var_inc;
                    if (level[v] == decision_level()) pathC++;
                    else learnt.push_back(q);
                }
            }
            while (idx >= 0 && !seen[abs(trail[idx])]) idx--;
            p = trail[idx--];
            seen[abs(p)] = 0;
            pathC--;
            if (pathC <= 0) break;
            int r = reason[abs(p)];
            if (r < 0) break;
            cl = &F.clauses[r].lits;
        }
        learnt.insert(learnt.begin(), -p);
        int bt = 0;
        for (int i = 1; i < (int)learnt.size(); ++i) bt = max(bt, level[abs(learnt[i])]);
        var_inc *= 1.05;
        return {learnt, bt};
    }

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

    int pick_branch() {
        int best = 0;
        double ba = -1.0;
        for (int v = 1; v <= F.nvars; ++v) {
            if (assigns[v] == 0 && activity[v] > ba) {
                ba = activity[v];
                best = v;
            }
        }
        return best;
    }

    void add_clause(const vector<int> &lits, bool learnt) {
        Clause c;
        c.lits = lits;
        c.learnt = learnt;
        c.w0 = 0;
        c.w1 = lits.size() > 1 ? 1 : 0;
        int ci = (int)F.clauses.size();
        F.clauses.push_back(std::move(c));
        watches[lit_index(F.clauses[ci].lits[F.clauses[ci].w0])].push_back(ci);
        if (F.clauses[ci].w1 != F.clauses[ci].w0) {
            watches[lit_index(F.clauses[ci].lits[F.clauses[ci].w1])].push_back(ci);
        }
    }

    void write_rup_clause(const vector<int> &cl) {
        if (!proof_open) return;
        proof << "rup ";
        for (int l : cl) {
            proof << "1 ";
            if (l < 0) proof << "~";
            proof << "x" << abs(l) << " ";
        }
        proof << ">= 1 ;\n";
    }

    bool open_proof(const string &path) {
        proof.open(path);
        if (!proof) return false;
        proof_open = true;
        proof << "pseudo-Boolean proof version 3.0\n";
        return true;
    }

    void finish_unsat_proof() {
        proof << "rup >= 1 ;\n";
        proof << "output NONE ;\n";
        proof << "conclusion UNSAT : -1 ;\n";
        proof << "end pseudo-Boolean proof;\n";
        proof.close();
    }

    int solve(const string &proof_path, vector<char> &model) {
        if (!open_proof(proof_path)) return 0;
        int confl = propagate();
        if (confl >= 0) {
            finish_unsat_proof();
            return 20;
        }
        long long conflicts = 0;
        while (elapsed_sec() < 585.0) {
            confl = propagate();
            if (confl >= 0) {
                conflicts++;
                if (decision_level() == 0) {
                    finish_unsat_proof();
                    return 20;
                }
                auto [learnt, bt] = analyze(confl);
                bump_clause(learnt);
                write_rup_clause(learnt);
                backtrack(bt);
                add_clause(learnt, true);
                enqueue(learnt[0], (int)F.clauses.size() - 1);
                if (conflicts % 5000 == 0) {
                    cerr << "c conflicts " << conflicts << " level " << decision_level()
                         << " clauses " << F.clauses.size() << " time " << elapsed_sec() << "\n";
                }
            } else {
                int v = pick_branch();
                if (v == 0) {
                    model = assigns;
                    proof.close();
                    return 10;
                }
                trail_lim.push_back((int)trail.size());
                int lit = F.majority[v] == 1 ? -v : v;
                enqueue(lit, -1);
            }
        }
        proof.close();
        return 0;
    }
};

int main(int argc, char **argv) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    g_start = chrono::steady_clock::now();
    if (argc != 3) {
        fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Formula F;
    if (!parse_dimacs(argv[1], F)) {
        cout << "s UNKNOWN\n";
        return 0;
    }
    cout << "c parsed vars=" << F.nvars << " clauses=" << F.clauses.size() << "\n";

    vector<char> model;
    LocalSearch ls(F);
    int max_width = 0;
    for (const Clause &c : F.clauses) max_width = max<int>(max_width, c.lits.size());
    double local_limit = 5.0;
    if (max_width <= 9) local_limit = 1.5;
    else if (max_width == 10) local_limit = 4.0;
    if (ls.solve(local_limit, model)) {
        cout << "c local-search solved in " << elapsed_sec() << " seconds\n";
        print_model(model);
        return 10;
    }

    cout << "c local-search inconclusive; entering watched CDCL\n";
    CDCL cdcl(F);
    int r = cdcl.solve(argv[2], model);
    if (r == 10) {
        if (!verify_model(F, model)) {
            cout << "s UNKNOWN\n";
            return 0;
        }
        print_model(model);
        return 10;
    }
    if (r == 20) {
        cout << "s UNSATISFIABLE\n";
        return 20;
    }
    cout << "s UNKNOWN\n";
    return 0;
}
