#include <algorithm>
#include <chrono>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <queue>
#include <string>
#include <vector>

using namespace std;

#ifndef BRANCH_MODE
#define BRANCH_MODE 3
#endif

#ifndef INIT_PHASE
#define INIT_PHASE 1
#endif

struct FastInput {
    static constexpr size_t BUFSZ = 1 << 20;
    FILE* f = nullptr;
    char buf[BUFSZ];
    size_t pos = 0, len = 0;

    explicit FastInput(const string& path) {
        f = fopen(path.c_str(), "rb");
    }
    ~FastInput() {
        if (f) fclose(f);
    }
    bool good() const { return f != nullptr; }

    int getch() {
        if (pos >= len) {
            len = fread(buf, 1, BUFSZ, f);
            pos = 0;
            if (len == 0) return EOF;
        }
        return (unsigned char)buf[pos++];
    }

    void skip_line() {
        int c;
        while ((c = getch()) != EOF && c != '\n') {}
    }

    bool read_token(string& out) {
        out.clear();
        int c;
        while (true) {
            c = getch();
            if (c == EOF) return false;
            if (isspace(c)) continue;
            break;
        }
        do {
            out.push_back((char)c);
            c = getch();
        } while (c != EOF && !isspace(c));
        return true;
    }

    bool read_int(int& out) {
        int c;
        while (true) {
            c = getch();
            if (c == EOF) return false;
            if (isspace(c)) continue;
            if (c == 'c') {
                skip_line();
                continue;
            }
            break;
        }
        int sign = 1;
        if (c == '-') {
            sign = -1;
            c = getch();
        }
        int x = 0;
        while (c != EOF && isdigit(c)) {
            x = x * 10 + (c - '0');
            c = getch();
        }
        out = sign * x;
        return true;
    }
};

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

struct Solver {
    int nvars = 0;
    vector<Clause> clauses;
    vector<vector<int>> watches;
    vector<signed char> val;
    vector<int> lev, reason, trail, trail_lim, seen, analyze_stack;
    vector<double> activity;
    vector<signed char> phase;
    priority_queue<pair<double,int>> heap;
    int qhead = 0;
    double var_inc = 1.0, var_decay = 0.95;
    long long conflicts = 0, decisions = 0, propagations = 0;
    bool force_activity = false;
    ofstream proof;
    chrono::steady_clock::time_point start;
    double time_limit = 570.0;

    explicit Solver(const string& proof_path) : proof(proof_path) {
        proof << "pseudo-Boolean proof version 3.0\n";
        start = chrono::steady_clock::now();
    }

    static int idx(int lit) {
        int v = abs(lit);
        return (v << 1) ^ (lit < 0);
    }
    int lit_value(int lit) const {
        signed char x = val[abs(lit)];
        if (!x) return 0;
        return ((lit > 0) == (x > 0)) ? 1 : -1;
    }
    int level() const { return (int)trail_lim.size(); }

    int initial_phase_value() const {
#if INIT_PHASE >= 0
        return 1;
#else
        return -1;
#endif
    }

    int pick_activity_var() {
        while (!heap.empty()) {
            int v = heap.top().second;
            double a = heap.top().first;
            heap.pop();
            if (val[v] == 0 && a <= activity[v] + 1e-12) return v;
        }
        for (int v = 1; v <= nvars; ++v) {
            if (val[v] == 0) return v;
        }
        return 0;
    }

    bool timed_out() const {
        auto now = chrono::steady_clock::now();
        return chrono::duration<double>(now - start).count() > time_limit;
    }

    bool enqueue(int lit, int rsn) {
        int v = abs(lit);
        signed char want = lit > 0 ? 1 : -1;
        if (val[v] == want) return true;
        if (val[v] == -want) return false;
        val[v] = want;
        lev[v] = level();
        reason[v] = rsn;
        phase[v] = want;
        trail.push_back(lit);
        return true;
    }

    void add_watch(int lit, int ci) {
        watches[idx(lit)].push_back(ci);
    }

    void attach_clause(int ci) {
        auto& c = clauses[ci].lits;
        if (c.size() == 1) add_watch(c[0], ci);
        else {
            add_watch(c[0], ci);
            add_watch(c[1], ci);
        }
    }

    int add_clause_initial(vector<int>& c) {
        sort(c.begin(), c.end(), [](int a, int b) {
            if (abs(a) != abs(b)) return abs(a) < abs(b);
            return a < b;
        });
        vector<int> out;
        int lastv = 0, lastlit = 0;
        for (int lit : c) {
            int v = abs(lit);
            if (v == lastv) {
                if (lit == -lastlit) return 0; // tautology
                continue;
            }
            out.push_back(lit);
            lastv = v;
            lastlit = lit;
        }
        if (out.empty()) return -1;

        vector<int> nonfalse;
        nonfalse.reserve(out.size());
        for (int lit : out) {
            int lv = lit_value(lit);
            if (lv == 1) return 0;
            if (lv != -1) nonfalse.push_back(lit);
        }
        if (nonfalse.empty()) return -1;

        int unit_lit = 0;
        out.swap(nonfalse);
        if (out.size() == 1) {
            unit_lit = out[0];
        }

        int ci = (int)clauses.size();
        clauses.push_back({out, false});
        attach_clause(ci);
        if (unit_lit != 0 && !enqueue(unit_lit, ci)) return -1;
        for (int lit : out) {
            int v = abs(lit);
            activity[v] += 1.0;
        }
        return 0;
    }

    void activity_resize() {
        if ((int)activity.size() < nvars + 1) activity.assign(nvars + 1, 0.0);
    }

    int propagate() {
        while (qhead < (int)trail.size()) {
            int lit = trail[qhead++];
            ++propagations;
            auto& ws = watches[idx(-lit)];
            int j = 0;
            for (int i = 0; i < (int)ws.size(); ++i) {
                int ci = ws[i];
                auto& c = clauses[ci].lits;
                if (c.size() == 1) {
                    if (lit_value(c[0]) == -1) {
                        while (i < (int)ws.size()) ws[j++] = ws[i++];
                        ws.resize(j);
                        return ci;
                    }
                    ws[j++] = ci;
                    continue;
                }
                if (c[0] == -lit) swap(c[0], c[1]);
                int other = c[0];
                if (lit_value(other) == 1) {
                    ws[j++] = ci;
                    continue;
                }
                bool moved = false;
                for (int k = 2; k < (int)c.size(); ++k) {
                    if (lit_value(c[k]) != -1) {
                        swap(c[1], c[k]);
                        watches[idx(c[1])].push_back(ci);
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;
                ws[j++] = ci;
                if (lit_value(other) == -1) {
                    while (++i < (int)ws.size()) ws[j++] = ws[i];
                    ws.resize(j);
                    return ci;
                }
                if (!enqueue(other, ci)) {
                    while (++i < (int)ws.size()) ws[j++] = ws[i];
                    ws.resize(j);
                    return ci;
                }
            }
            ws.resize(j);
        }
        return -1;
    }

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

    void bump_var(int v) {
        activity[v] += var_inc;
        if (activity[v] > 1e100) {
            for (int i = 1; i <= nvars; ++i) activity[i] *= 1e-100;
            var_inc *= 1e-100;
        }
        heap.push({activity[v], v});
    }

    int pick_branch_var() {
#if BRANCH_MODE == 1
        for (int v = 1; v <= nvars; ++v) {
            if (val[v] == 0) return v;
        }
        return 0;
#elif BRANCH_MODE == 2
        for (int v = nvars; v >= 1; --v) {
            if (val[v] == 0) return v;
        }
        return 0;
#elif BRANCH_MODE == 3
        if (nvars >= 200000 && !force_activity) {
            for (int v = 1; v <= nvars; ++v) {
                if (val[v] == 0) return v;
            }
            return 0;
        }
        return pick_activity_var();
#else
        return pick_activity_var();
#endif
    }

    void write_rup_clause(const vector<int>& c) {
        proof << "rup ";
        for (int lit : c) {
            proof << "1 ";
            if (lit < 0) proof << "~";
            proof << "x" << abs(lit) << " ";
        }
        proof << ">= 1 ;\n";
    }

    int add_learned(vector<int>& c) {
        write_rup_clause(c);
        int ci = (int)clauses.size();
        clauses.push_back({c, true});
        attach_clause(ci);
        return ci;
    }

    int analyze(int confl, vector<int>& out) {
        out.clear();
        out.push_back(0);
        int path_count = 0;
        int p = 0;
        int idx_trail = (int)trail.size() - 1;
        int bt = 0;
        analyze_stack.clear();

        auto visit = [&](int lit) {
            int v = abs(lit);
            if (seen[v] || lev[v] == 0) return;
            seen[v] = 1;
            analyze_stack.push_back(v);
            bump_var(v);
            if (lev[v] == level()) ++path_count;
            else {
                out.push_back(lit);
                bt = max(bt, lev[v]);
            }
        };

        for (int lit : clauses[confl].lits) visit(lit);

        while (path_count > 0) {
            while (idx_trail >= 0 && !seen[abs(trail[idx_trail])]) --idx_trail;
            p = trail[idx_trail--];
            int v = abs(p);
            seen[v] = 0;
            --path_count;
            int r = reason[v];
            if (r != -1) {
                for (int lit : clauses[r].lits) {
                    if (abs(lit) == v) continue;
                    visit(lit);
                }
            }
        }

        out[0] = -p;
        for (int v : analyze_stack) seen[v] = 0;
        if (out.size() == 1) bt = 0;
        return bt;
    }

    bool all_clauses_satisfied() const {
        for (const auto& cl : clauses) {
            bool sat = false;
            for (int lit : cl.lits) {
                int v = val[abs(lit)];
                if (v && ((lit > 0) == (v > 0))) {
                    sat = true;
                    break;
                }
            }
            if (!sat) return false;
        }
        return true;
    }

    bool original_dimacs_satisfied(const string& path) const {
        FastInput in(path);
        if (!in.good()) return false;
        string tok;
        bool saw_header = false;
        while (in.read_token(tok)) {
            if (tok == "c") {
                in.skip_line();
                continue;
            }
            if (tok == "p") {
                string fmt, ns, ms;
                if (!in.read_token(fmt) || !in.read_token(ns) || !in.read_token(ms)) return false;
                saw_header = true;
                break;
            }
        }
        if (!saw_header) return false;

        bool sat = false;
        bool saw_lit = false;
        int lit;
        while (in.read_int(lit)) {
            if (lit == 0) {
                if (saw_lit && !sat) return false;
                sat = false;
                saw_lit = false;
            } else {
                saw_lit = true;
                int v = abs(lit);
                if (v <= nvars && val[v] && ((lit > 0) == (val[v] > 0))) sat = true;
            }
        }
        return !saw_lit || sat;
    }

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

    int parse_dimacs(const string& path) {
        FastInput in(path);
        if (!in.good()) return 0;
        string tok;
        bool saw_header = false;
        while (in.read_token(tok)) {
            if (tok == "c") {
                in.skip_line();
                continue;
            }
            if (tok == "p") {
                string fmt, ns, ms;
                if (!in.read_token(fmt) || !in.read_token(ns) || !in.read_token(ms)) return 0;
                nvars = atoi(ns.c_str());
                int m = atoi(ms.c_str());
                clauses.reserve(m + 100000);
                watches.assign(2 * (nvars + 1), {});
                val.assign(nvars + 1, 0);
                lev.assign(nvars + 1, 0);
                reason.assign(nvars + 1, -1);
                seen.assign(nvars + 1, 0);
                activity.assign(nvars + 1, 0.0);
                phase.assign(nvars + 1, initial_phase_value());
                saw_header = true;
                break;
            }
        }
        if (!saw_header) return 0;

        vector<int> cur;
        int lit;
        while (in.read_int(lit)) {
            if (lit == 0) {
                if (add_clause_initial(cur) < 0) return -1;
                cur.clear();
                if (qhead < (int)trail.size()) {
                    int confl = propagate();
                    if (confl != -1) return -1;
                }
            } else {
                cur.push_back(lit);
            }
        }
        if (!cur.empty()) {
            if (add_clause_initial(cur) < 0) return -1;
        }
        int confl = propagate();
        if (confl != -1) return -1;
        for (int v = 1; v <= nvars; ++v) heap.push({activity[v], v});
        return 1;
    }

    int solve() {
        int confl = propagate();
        if (confl != -1) {
            finish_unsat_proof();
            return 20;
        }

        vector<int> learnt;
        int restart_base = 100;
        int next_restart = restart_base;
        while (true) {
            if (timed_out()) return 0;
            confl = propagate();
            if (confl != -1) {
                ++conflicts;
                if (level() == 0) {
                    finish_unsat_proof();
                    return 20;
                }
                int bt = analyze(confl, learnt);
                var_inc /= var_decay;
                backtrack(bt);
                int ci = add_learned(learnt);
                if (!enqueue(learnt[0], ci)) {
                    finish_unsat_proof();
                    return 20;
                }
                if (conflicts >= next_restart) {
                    backtrack(0);
                    next_restart += restart_base;
                    restart_base = min(restart_base * 3 / 2 + 1, 10000);
                }
            } else {
                if (nvars >= 200000 && !force_activity &&
                    (conflicts >= 10 || decisions >= 2000 || propagations >= 3000000)) {
                    backtrack(0);
                    force_activity = true;
                }
                int v = pick_branch_var();
                if (v == 0) {
                    if (all_clauses_satisfied()) return 10;
                    return 0;
                }
                ++decisions;
                trail_lim.push_back((int)trail.size());
                int lit = phase[v] >= 0 ? v : -v;
                enqueue(lit, -1);
            }
        }
    }
};

struct RootProbe {
    struct RClause {
        int start = 0;
        int size = 0;
        int next0 = -1;
        int next1 = -1;
    };

    int nvars = 0;
    vector<signed char> val;
    vector<int> trail;
    int qhead = 0;
    vector<int> heads;
    vector<int> lits;
    vector<RClause> clauses;
    long long parsed_clauses = 0;
    long long stored_clauses = 0;
    long long propagations = 0;

    static int idx(int lit) {
        int v = abs(lit);
        return (v << 1) ^ (lit < 0);
    }

    int lit_value(int lit) const {
        signed char x = val[abs(lit)];
        if (!x) return 0;
        return ((lit > 0) == (x > 0)) ? 1 : -1;
    }

    bool enqueue(int lit) {
        int v = abs(lit);
        signed char want = lit > 0 ? 1 : -1;
        if (val[v] == want) return true;
        if (val[v] == -want) return false;
        val[v] = want;
        trail.push_back(lit);
        return true;
    }

    void attach_watch(int lit, int ci, int wp) {
        int wi = idx(lit);
        if (wp == 0) {
            clauses[ci].next0 = heads[wi];
        } else {
            clauses[ci].next1 = heads[wi];
        }
        heads[wi] = ci;
    }

    bool add_reduced_clause(const vector<int>& reduced) {
        int ci = (int)clauses.size();
        RClause rc;
        rc.start = (int)lits.size();
        rc.size = (int)reduced.size();
        clauses.push_back(rc);
        lits.insert(lits.end(), reduced.begin(), reduced.end());
        attach_watch(reduced[0], ci, 0);
        attach_watch(reduced[1], ci, 1);
        ++stored_clauses;
        return true;
    }

    bool add_clause(vector<int>& c) {
        ++parsed_clauses;
        sort(c.begin(), c.end(), [](int a, int b) {
            if (abs(a) != abs(b)) return abs(a) < abs(b);
            return a < b;
        });
        vector<int> out;
        int lastv = 0, lastlit = 0;
        for (int lit : c) {
            int v = abs(lit);
            if (v == lastv) {
                if (lit == -lastlit) return true;
                continue;
            }
            out.push_back(lit);
            lastv = v;
            lastlit = lit;
        }
        if (out.empty()) return false;

        vector<int> reduced;
        reduced.reserve(out.size());
        for (int lit : out) {
            int lv = lit_value(lit);
            if (lv == 1) return true;
            if (lv == 0) reduced.push_back(lit);
        }
        if (reduced.empty()) return false;
        if (reduced.size() == 1) return enqueue(reduced[0]);
        return add_reduced_clause(reduced);
    }

    bool propagate() {
        while (qhead < (int)trail.size()) {
            int lit = trail[qhead++];
            ++propagations;
            int wi = idx(-lit);
            int* link = &heads[wi];
            while (*link != -1) {
                int ci = *link;
                RClause& rc = clauses[ci];
                int s = rc.start;
                int wp;
                if (lits[s] == -lit) {
                    wp = 0;
                } else if (rc.size > 1 && lits[s + 1] == -lit) {
                    wp = 1;
                } else {
                    // Stale entry from a moved watch; unlink defensively.
                    *link = (rc.next0 == ci ? rc.next1 : rc.next0);
                    continue;
                }

                int other_wp = 1 - wp;
                int other = lits[s + other_wp];
                int* next_ptr = (wp == 0) ? &rc.next0 : &rc.next1;
                if (lit_value(other) == 1) {
                    link = next_ptr;
                    continue;
                }

                bool moved = false;
                for (int k = 2; k < rc.size; ++k) {
                    if (lit_value(lits[s + k]) != -1) {
                        int new_lit = lits[s + k];
                        swap(lits[s + wp], lits[s + k]);
                        *link = *next_ptr;
                        *next_ptr = heads[idx(new_lit)];
                        heads[idx(new_lit)] = ci;
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;

                if (lit_value(other) == -1) return false;
                if (!enqueue(other)) return false;
                link = next_ptr;
            }
        }
        return true;
    }

    int run(const string& path) {
        FastInput in(path);
        if (!in.good()) return 0;
        string tok;
        bool saw_header = false;
        while (in.read_token(tok)) {
            if (tok == "c") {
                in.skip_line();
                continue;
            }
            if (tok == "p") {
                string fmt, ns, ms;
                if (!in.read_token(fmt) || !in.read_token(ns) || !in.read_token(ms)) return 0;
                nvars = atoi(ns.c_str());
                int m = atoi(ms.c_str());
                val.assign(nvars + 1, 0);
                heads.assign(2 * (nvars + 1), -1);
                clauses.reserve(min(m, 1000000));
                lits.reserve(min(m * 2, 4000000));
                saw_header = true;
                break;
            }
        }
        if (!saw_header) return 0;

        vector<int> cur;
        int lit;
        while (in.read_int(lit)) {
            if (lit == 0) {
                if (!add_clause(cur)) return 20;
                cur.clear();
                if (qhead < (int)trail.size() && !propagate()) return 20;
            } else {
                cur.push_back(lit);
            }
        }
        if (!cur.empty() && !add_clause(cur)) return 20;
        if (!propagate()) return 20;
        return 1;
    }
};

static void write_trivial_unsat_proof(const string& proof_path) {
    ofstream proof(proof_path);
    proof << "pseudo-Boolean proof version 3.0\n";
    proof << "rup 1 x1 >= 2 ;\n";
    proof << "output NONE ;\n";
    proof << "conclusion UNSAT : -1 ;\n";
    proof << "end pseudo-Boolean proof ;\n";
}

static bool init_solver_from_probe(Solver& s, RootProbe& rp) {
    s.nvars = rp.nvars;
    s.clauses.clear();
    s.clauses.reserve(rp.clauses.size() + 100000);
    s.watches.assign(2 * (s.nvars + 1), {});
    s.val = rp.val;
    s.lev.assign(s.nvars + 1, 0);
    s.reason.assign(s.nvars + 1, -1);
    s.seen.assign(s.nvars + 1, 0);
    s.activity.assign(s.nvars + 1, 0.0);
    s.phase.assign(s.nvars + 1, s.initial_phase_value());
    s.trail = rp.trail;
    s.trail_lim.clear();
    s.qhead = (int)s.trail.size();

    vector<int> tmp;
    for (const auto& rc : rp.clauses) {
        tmp.clear();
        tmp.reserve(rc.size);
        bool sat = false;
        for (int k = 0; k < rc.size; ++k) {
            int lit = rp.lits[rc.start + k];
            int lv = s.lit_value(lit);
            if (lv == 1) {
                sat = true;
                break;
            }
            if (lv == 0) tmp.push_back(lit);
        }
        if (sat) continue;
        if (tmp.empty()) return false;
        if (s.add_clause_initial(tmp) < 0) return false;
        if (s.qhead < (int)s.trail.size()) {
            int confl = s.propagate();
            if (confl != -1) return false;
        }
    }
    int confl = s.propagate();
    if (confl != -1) return false;
    for (int v = 1; v <= s.nvars; ++v) s.heap.push({s.activity[v], v});

    rp.heads.clear();
    rp.lits.clear();
    rp.clauses.clear();
    rp.trail.clear();
    rp.val.clear();
    return true;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    RootProbe rp;
    int root_res = rp.run(argv[1]);
    if (root_res == 20) {
        write_trivial_unsat_proof(argv[2]);
        cout << "c root-probe n=" << rp.nvars << " parsed=" << rp.parsed_clauses
             << " stored=" << rp.stored_clauses << " propagations=" << rp.propagations << "\n";
        cout << "s UNSATISFIABLE\n";
        return 20;
    }
    if (root_res == 0) {
        cout << "s UNKNOWN\n";
        return 0;
    }

    Solver s(argv[2]);
    if (!init_solver_from_probe(s, rp)) {
        s.finish_unsat_proof();
        cout << "c parsed n=" << s.nvars << " clauses=" << s.clauses.size() << "\n";
        cout << "c conflicts=" << s.conflicts << " decisions=" << s.decisions << " propagations=" << s.propagations << "\n";
        cout << "s UNSATISFIABLE\n";
        return 20;
    }
    cout << "c parsed n=" << s.nvars << " clauses=" << s.clauses.size() << "\n";
    int res = s.solve();
    if (res == 20) {
        cout << "c conflicts=" << s.conflicts << " decisions=" << s.decisions << " propagations=" << s.propagations << "\n";
        cout << "s UNSATISFIABLE\n";
        return 20;
    }
    if (res == 10) {
        for (int v = 1; v <= s.nvars; ++v) if (s.val[v] == 0) s.val[v] = 1;
        if (!s.all_clauses_satisfied() || !s.original_dimacs_satisfied(argv[1])) {
            cout << "s UNKNOWN\n";
            return 0;
        }
        cout << "c conflicts=" << s.conflicts << " decisions=" << s.decisions << " propagations=" << s.propagations << "\n";
        cout << "s SATISFIABLE\n";
        const int per_line = 20;
        for (int v = 1; v <= s.nvars; ++v) {
            if ((v - 1) % per_line == 0) cout << "v ";
            cout << (s.val[v] > 0 ? v : -v) << ' ';
            if (v % per_line == 0) cout << "0\n";
        }
        if (s.nvars % per_line != 0) cout << "0\n";
        return 10;
    }
    cout << "c conflicts=" << s.conflicts << " decisions=" << s.decisions << " propagations=" << s.propagations << "\n";
    cout << "s UNKNOWN\n";
    return 0;
}
