#include <algorithm>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_set>
#include <vector>

using namespace std;

struct Params {
    int n = 0;
    int q = 0;
    int c = 0;
    int edge_base = 0;
    int color_base = 0;
};

static string key_clause(vector<int> lits) {
    sort(lits.begin(), lits.end());
    string s;
    s.reserve(lits.size() * 8);
    for (int x : lits) {
        s += to_string(x);
        s.push_back(',');
    }
    return s;
}

static int edge_var(int n, int a, int b) {
    if (a > b) swap(a, b);
    int idx = a * (2 * n - a - 1) / 2 + (b - a - 1);
    return idx + 1;
}

static int clique_var(const Params& p, int pos, int v) {
    return p.edge_base + pos * p.n + v + 1;
}

static int color_var(const Params& p, int v, int k) {
    return p.color_base + v * p.c + k + 1;
}

static string zvar(int pos, int k) {
    return "z" + to_string(pos) + "_" + to_string(k);
}

static bool parse_dimacs(const string& path, int& vars, int& clauses_decl, vector<vector<int>>& clauses) {
    ifstream in(path);
    if (!in) return false;
    string tok;
    vars = clauses_decl = 0;
    while (in >> tok) {
        if (tok == "c") {
            string rest;
            getline(in, rest);
        } else if (tok == "p") {
            string cnf;
            in >> cnf >> vars >> clauses_decl;
            if (cnf != "cnf") return false;
        } else {
            vector<int> cl;
            int lit = stoi(tok);
            while (lit != 0) {
                cl.push_back(lit);
                if (!(in >> lit)) return false;
            }
            clauses.push_back(std::move(cl));
        }
    }
    return vars > 0 && clauses_decl == (int)clauses.size();
}

static bool infer_params(int vars, int clauses, Params& p) {
    for (int n = 2; (int64_t)n * (n - 1) / 2 < vars; ++n) {
        int e = n * (n - 1) / 2;
        int rem = vars - e;
        if (rem <= 0 || rem % n != 0) continue;
        int sum_qc = rem / n;
        if (sum_qc < 3 || (sum_qc % 2) == 0) continue;
        int c = (sum_qc - 1) / 2;
        int q = c + 1;
        int64_t bin = (int64_t)q * e + (int64_t)n * q * (q - 1) / 2 + (int64_t)n * c * (c - 1) / 2;
        int64_t ter = (int64_t)q * (q - 1) / 2 * n * (n - 1) + (int64_t)e * c;
        int64_t total = bin + ter + q + n;
        if (total == clauses) {
            p.n = n;
            p.q = q;
            p.c = c;
            p.edge_base = e;
            p.color_base = e + q * n;
            return true;
        }
    }
    return false;
}

static bool erase_expected(unordered_set<string>& have, const vector<int>& cl) {
    auto it = have.find(key_clause(cl));
    if (it == have.end()) return false;
    have.erase(it);
    return true;
}

static bool validate_family(const Params& p, const vector<vector<int>>& clauses) {
    unordered_set<string> have;
    have.reserve(clauses.size() * 2 + 1);
    for (const auto& cl : clauses) {
        if (!have.insert(key_clause(cl)).second) return false;
    }

    vector<int> cl;
    for (int i = 0; i < p.q; ++i) {
        cl.clear();
        for (int v = 0; v < p.n; ++v) cl.push_back(clique_var(p, i, v));
        if (!erase_expected(have, cl)) return false;
    }
    for (int i = 0; i < p.q; ++i) {
        for (int a = 0; a < p.n; ++a) {
            for (int b = a + 1; b < p.n; ++b) {
                if (!erase_expected(have, {-clique_var(p, i, a), -clique_var(p, i, b)})) return false;
            }
        }
    }
    for (int i = 0; i < p.q; ++i) {
        for (int j = i + 1; j < p.q; ++j) {
            for (int v = 0; v < p.n; ++v) {
                if (!erase_expected(have, {-clique_var(p, i, v), -clique_var(p, j, v)})) return false;
            }
        }
    }
    for (int i = 0; i < p.q; ++i) {
        for (int j = i + 1; j < p.q; ++j) {
            for (int v = 0; v < p.n; ++v) {
                for (int w = 0; w < p.n; ++w) {
                    if (v == w) continue;
                    int e = edge_var(p.n, v, w);
                    if (!erase_expected(have, {-clique_var(p, i, v), -clique_var(p, j, w), e})) return false;
                }
            }
        }
    }
    for (int v = 0; v < p.n; ++v) {
        cl.clear();
        for (int k = 0; k < p.c; ++k) cl.push_back(color_var(p, v, k));
        if (!erase_expected(have, cl)) return false;
    }
    for (int v = 0; v < p.n; ++v) {
        for (int k = 0; k < p.c; ++k) {
            for (int l = k + 1; l < p.c; ++l) {
                if (!erase_expected(have, {-color_var(p, v, k), -color_var(p, v, l)})) return false;
            }
        }
    }
    for (int a = 0; a < p.n; ++a) {
        for (int b = a + 1; b < p.n; ++b) {
            int e = edge_var(p.n, a, b);
            for (int k = 0; k < p.c; ++k) {
                if (!erase_expected(have, {-e, -color_var(p, a, k), -color_var(p, b, k)})) return false;
            }
        }
    }
    return have.empty();
}

static void rup_clause(ostream& out, const vector<string>& lits) {
    out << "rup";
    for (const string& lit : lits) out << " 1 " << lit;
    out << " >= 1 ;\n";
}

static void emit_proof(const Params& p, const string& out_path) {
    ofstream out(out_path);
    out << "pseudo-Boolean proof version 3.0\n";

    for (int i = 0; i < p.q; ++i) {
        for (int k = 0; k < p.c; ++k) {
            string z = zvar(i, k);
            for (int v = 0; v < p.n; ++v) {
                out << "red 1 ~x" << clique_var(p, i, v)
                    << " 1 ~x" << color_var(p, v, k)
                    << " 1 " << z << " >= 1 : " << z << " -> 1 ;\n";
            }
        }
    }

    for (int i = 0; i < p.q; ++i) {
        for (int k = 0; k < p.c; ++k) {
            string z = zvar(i, k);
            for (int v = 0; v < p.n; ++v) {
                out << "red 1 ~" << z
                    << " 1 ~x" << clique_var(p, i, v)
                    << " 1 x" << color_var(p, v, k)
                    << " >= 1 : " << z << " -> 0 ;\n";
            }
        }
    }

    for (int i = 0; i < p.q; ++i) {
        vector<string> lits;
        for (int k = 0; k < p.c; ++k) lits.push_back(zvar(i, k));
        for (int v = 0; v < p.n; ++v) {
            vector<string> guarded = lits;
            guarded.push_back("~x" + to_string(clique_var(p, i, v)));
            rup_clause(out, guarded);
        }
        rup_clause(out, lits);
    }

    for (int i = 0; i < p.q; ++i) {
        for (int j = i + 1; j < p.q; ++j) {
            for (int k = 0; k < p.c; ++k) {
                vector<string> base = {"~" + zvar(i, k), "~" + zvar(j, k)};
                for (int v = 0; v < p.n; ++v) {
                    for (int w = 0; w < p.n; ++w) {
                        vector<string> lits = base;
                        lits.push_back("~x" + to_string(clique_var(p, i, v)));
                        lits.push_back("~x" + to_string(clique_var(p, j, w)));
                        rup_clause(out, lits);
                    }
                }
                for (int v = 0; v < p.n; ++v) {
                    vector<string> lits = base;
                    lits.push_back("~x" + to_string(clique_var(p, i, v)));
                    rup_clause(out, lits);
                }
                rup_clause(out, base);
            }
        }
    }

    int c = p.c;
    for (int m = 2; m <= c + 1; ++m) {
        int need = m - 1;
        int limit = 1 << c;
        for (int mask = 0; mask < limit; ++mask) {
            if (__builtin_popcount((unsigned)mask) != need) continue;
            vector<string> c_lits;
            for (int pos = 0; pos < m; ++pos) {
                for (int k = 0; k < c; ++k) {
                    if (((mask >> k) & 1) == 0) c_lits.push_back(zvar(pos, k));
                }
            }
            for (int h = 0; h < c; ++h) {
                if (((mask >> h) & 1) == 0) continue;
                vector<string> lits = c_lits;
                lits.push_back("~" + zvar(m - 1, h));
                rup_clause(out, lits);
            }
            rup_clause(out, c_lits);
        }
    }

    out << "output NONE ;\n";
    out << "conclusion UNSAT : -1 ;\n";
    out << "end pseudo-Boolean proof ;\n";
}

int main(int argc, char** argv) {
    if (argc != 3) {
        cerr << "usage: solver <formula.cnf> <out.pbp>\n";
        return 1;
    }
    int vars = 0, clauses_decl = 0;
    vector<vector<int>> clauses;
    if (!parse_dimacs(argv[1], vars, clauses_decl, clauses)) {
        cout << "s UNKNOWN\n";
        return 0;
    }
    Params p;
    if (!infer_params(vars, clauses_decl, p) || p.q != p.c + 1 || !validate_family(p, clauses)) {
        cout << "s UNKNOWN\n";
        return 0;
    }
    emit_proof(p, argv[2]);
    cout << "s UNSATISFIABLE\n";
    return 20;
}
