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

using std::string;
using std::vector;

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

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

struct Solver {
    int nvars = 0;
    vector<Clause> clauses;
    vector<vector<int>> watches;
    vector<int8_t> assigns;   // 1 true, -1 false, 0 unset
    vector<int> level;
    vector<int> reason;
    vector<int> trail;
    vector<int> trail_lim;
    int qhead = 0;
    vector<double> activity;
    vector<int> polarity;     // preferred decision literal polarity, +/-1
    double var_inc = 1.0;
    vector<vector<int>> proof_clauses;
    bool parse_error = false;
    bool initial_empty = false;

    explicit Solver(int n = 0) { init(n); }

    void init(int n) {
        nvars = n;
        watches.assign(2 * nvars + 2, {});
        assigns.assign(nvars + 1, 0);
        level.assign(nvars + 1, 0);
        reason.assign(nvars + 1, -1);
        activity.assign(nvars + 1, 0.0);
        polarity.assign(nvars + 1, 1);
    }

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

    bool lit_true(int lit) const {
        int8_t v = assigns[var_of(lit)];
        return v != 0 && v == (lit > 0 ? 1 : -1);
    }
    bool lit_false(int lit) const {
        int8_t v = assigns[var_of(lit)];
        return v != 0 && v == (lit > 0 ? -1 : 1);
    }

    bool enqueue(int lit, int from) {
        int v = var_of(lit);
        int8_t 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 add_clause(vector<int> lits, bool learnt) {
        vector<int> clean;
        clean.reserve(lits.size());
        vector<int8_t> seen(nvars + 1, 0);
        for (int lit : lits) {
            if (lit == 0) continue;
            if (var_of(lit) < 1 || var_of(lit) > nvars) {
                parse_error = true;
                return -1;
            }
            int v = var_of(lit);
            int8_t sign = lit > 0 ? 1 : -1;
            if (seen[v] == sign) continue;
            if (seen[v] == -sign) return -2; // tautology
            seen[v] = sign;
            clean.push_back(lit);
            activity[var_of(lit)] += 1.0;
        }
        int id = (int)clauses.size();
        clauses.push_back({clean, learnt});
        if (clean.empty()) {
            initial_empty = true;
        } else if (clean.size() == 1) {
            if (!enqueue(clean[0], id)) initial_empty = true;
        } else {
            watches[lit_index(clean[0])].push_back(id);
            watches[lit_index(clean[1])].push_back(id);
        }
        return id;
    }

    int propagate() {
        while (qhead < (int)trail.size()) {
            int p = trail[qhead++];
            int false_lit = neg_lit(p);
            auto &ws = watches[lit_index(false_lit)];
            int out = 0;
            for (int k = 0; k < (int)ws.size(); ++k) {
                int ci = ws[k];
                Clause &c = clauses[ci];
                if (c.lits.size() == 1) {
                    ws[out++] = ci;
                    continue;
                }
                if (c.lits[0] != false_lit) std::swap(c.lits[0], c.lits[1]);
                int other = c.lits[1];
                if (lit_true(other)) {
                    ws[out++] = ci;
                    continue;
                }
                bool moved = false;
                for (int i = 2; i < (int)c.lits.size(); ++i) {
                    int lit = c.lits[i];
                    if (!lit_false(lit)) {
                        c.lits[0] = lit;
                        c.lits[i] = false_lit;
                        watches[lit_index(lit)].push_back(ci);
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;
                ws[out++] = ci;
                if (lit_false(other)) {
                    for (++k; k < (int)ws.size(); ++k) ws[out++] = ws[k];
                    ws.resize(out);
                    return ci;
                }
                if (!enqueue(other, ci)) {
                    for (++k; k < (int)ws.size(); ++k) ws[out++] = ws[k];
                    ws.resize(out);
                    return ci;
                }
            }
            ws.resize(out);
        }
        return -1;
    }

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

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

    void bump_clause(const vector<int> &lits) {
        for (int lit : lits) activity[var_of(lit)] += var_inc;
        var_inc *= 1.05;
        if (var_inc > 1e100) {
            for (int v = 1; v <= nvars; ++v) activity[v] *= 1e-100;
            var_inc *= 1e-100;
        }
    }

    void analyze(int confl, vector<int> &out_clause, int &backtrack) {
        vector<char> seen(nvars + 1, 0);
        out_clause.clear();
        out_clause.push_back(0);
        int path_count = 0;
        int p = 0;
        int idx = (int)trail.size() - 1;
        int ci = confl;
        while (true) {
            const Clause &c = clauses[ci];
            for (int lit : c.lits) {
                int v = var_of(lit);
                if (v == var_of(p)) continue;
                if (!seen[v] && level[v] > 0) {
                    seen[v] = 1;
                    if (level[v] == decision_level()) {
                        path_count++;
                    } else {
                        out_clause.push_back(lit);
                    }
                }
            }
            while (idx >= 0 && !seen[var_of(trail[idx])]) idx--;
            if (idx < 0) break;
            p = trail[idx--];
            seen[var_of(p)] = 0;
            path_count--;
            if (path_count <= 0) break;
            ci = reason[var_of(p)];
            if (ci < 0) break;
        }
        out_clause[0] = neg_lit(p);

        backtrack = 0;
        int best = 1;
        for (int i = 1; i < (int)out_clause.size(); ++i) {
            int lv = level[var_of(out_clause[i])];
            if (lv > backtrack) {
                backtrack = lv;
                best = i;
            }
        }
        if (out_clause.size() > 1) std::swap(out_clause[1], out_clause[best]);
    }

    int pick_branch_lit() const {
        int best = 0;
        double best_act = -1.0;
        for (int v = 1; v <= nvars; ++v) {
            if (assigns[v] == 0 && activity[v] > best_act) {
                best_act = activity[v];
                best = v;
            }
        }
        if (best == 0) return 0;
        return polarity[best] > 0 ? best : -best;
    }

    bool all_clauses_satisfied() const {
        for (const Clause &c : clauses) {
            if (c.learnt) continue;
            bool sat = false;
            for (int lit : c.lits) {
                if (lit_true(lit)) {
                    sat = true;
                    break;
                }
            }
            if (!sat) return false;
        }
        return true;
    }

    int solve() {
        int confl = initial_empty ? 0 : propagate();
        if (confl >= 0 || initial_empty) {
            proof_clauses.push_back({});
            return 20;
        }

        int conflicts = 0;
        int restart_limit = 100;
        while (true) {
            confl = propagate();
            if (confl >= 0) {
                conflicts++;
                if (decision_level() == 0) {
                    proof_clauses.push_back({});
                    return 20;
                }
                vector<int> learnt;
                int bt = 0;
                analyze(confl, learnt, bt);
                bump_clause(learnt);
                proof_clauses.push_back(learnt);
                cancel_until(bt);
                int id = add_clause(learnt, true);
                if (id >= 0) {
                    if (clauses[id].lits.size() == 1) {
                        if (!enqueue(clauses[id].lits[0], id)) {
                            proof_clauses.push_back({});
                            return 20;
                        }
                    } else {
                        if (!enqueue(clauses[id].lits[0], id)) {
                            proof_clauses.push_back({});
                            return 20;
                        }
                    }
                }
                if (conflicts >= restart_limit) {
                    cancel_until(0);
                    restart_limit = restart_limit + restart_limit / 2 + 50;
                    conflicts = 0;
                }
            } else {
                int next = pick_branch_lit();
                if (next == 0) {
                    return all_clauses_satisfied() ? 10 : 0;
                }
                new_decision_level();
                enqueue(next, -1);
            }
        }
    }
};

static bool parse_dimacs(const string &path, Solver &S) {
    std::ifstream in(path);
    if (!in) return false;
    string tok;
    int vars = 0, clauses = 0;
    while (in >> tok) {
        if (tok == "c") {
            string rest;
            std::getline(in, rest);
        } else if (tok == "p") {
            string fmt;
            in >> fmt >> vars >> clauses;
            if (fmt != "cnf" || vars < 0 || clauses < 0) return false;
            S.init(vars);
            break;
        } else {
            return false;
        }
    }
    if (vars == 0 && clauses != 0) return false;

    vector<int> lits;
    lits.reserve(16);
    int lit = 0;
    while (in >> lit) {
        if (lit == 0) {
            S.add_clause(lits, false);
            lits.clear();
        } else {
            lits.push_back(lit);
            int v = var_of(lit);
            if (v >= 1 && v <= S.nvars) {
                S.polarity[v] += (lit > 0 ? 1 : -1);
            }
        }
    }
    for (int v = 1; v <= S.nvars; ++v) S.polarity[v] = S.polarity[v] >= 0 ? 1 : -1;
    return !S.parse_error;
}

static void write_pb_clause(std::ofstream &out, const vector<int> &clause) {
    out << "rup ";
    for (int lit : clause) {
        out << "1 ";
        if (lit < 0) out << "~";
        out << "x" << var_of(lit) << " ";
    }
    out << ">= 1 ;\n";
}

static bool write_proof(const string &path, const vector<vector<int>> &proof) {
    std::ofstream out(path);
    if (!out) return false;
    out << "pseudo-Boolean proof version 3.0\n";
    for (const auto &c : proof) write_pb_clause(out, c);
    out << "output NONE ;\n";
    out << "conclusion UNSAT : -1 ;\n";
    out << "end pseudo-Boolean proof ;\n";
    return (bool)out;
}

static void print_model(const Solver &S) {
    std::cout << "s SATISFIABLE\n";
    std::cout << "v";
    int col = 1;
    for (int v = 1; v <= S.nvars; ++v) {
        int lit = S.assigns[v] >= 0 ? v : -v;
        std::cout << " " << lit;
        if (++col >= 20) {
            std::cout << " 0\nv";
            col = 1;
        }
    }
    std::cout << " 0\n";
}

int main(int argc, char **argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Solver S;
    if (!parse_dimacs(argv[1], S)) {
        std::cout << "c parse failure\ns UNKNOWN\n";
        return 0;
    }
    std::cout << "c vars " << S.nvars << " clauses " << S.clauses.size() << "\n";
    int res = S.solve();
    if (res == 10) {
        if (!S.all_clauses_satisfied()) {
            std::cout << "c internal model check failed\ns UNKNOWN\n";
            return 0;
        }
        print_model(S);
        return 10;
    }
    if (res == 20) {
        if (!write_proof(argv[2], S.proof_clauses)) {
            std::cout << "c could not write proof\ns UNKNOWN\n";
            return 0;
        }
        std::cout << "s UNSATISFIABLE\n";
        return 20;
    }
    std::cout << "s UNKNOWN\n";
    return 0;
}
