#include <algorithm>
#include <array>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>

using Clause = std::vector<int>;
using Row = std::vector<uint64_t>;

static bool get_bit(const Row& r, int bit) {
    return (r[bit >> 6] >> (bit & 63)) & 1ULL;
}

static void flip_bit(Row& r, int bit) {
    r[bit >> 6] ^= 1ULL << (bit & 63);
}

static void xor_row(Row& a, const Row& b) {
    for (size_t i = 0; i < a.size(); ++i) a[i] ^= b[i];
}

static int first_coeff_bit(const Row& r, int nvars) {
    const int full_words = nvars >> 6;
    const int rem = nvars & 63;
    for (int w = 0; w < full_words; ++w) {
        if (r[w]) return w * 64 + __builtin_ctzll(r[w]);
    }
    if (rem) {
        uint64_t mask = (1ULL << rem) - 1ULL;
        uint64_t x = r[full_words] & mask;
        if (x) return full_words * 64 + __builtin_ctzll(x);
    }
    return -1;
}

static bool parse_dimacs(const std::string& path, int& nvars, std::vector<Clause>& clauses) {
    std::ifstream in(path);
    if (!in) return false;

    std::string tok;
    int declared_clauses = -1;
    nvars = 0;
    while (in >> tok) {
        if (tok == "c") {
            std::string rest;
            std::getline(in, rest);
        } else if (tok == "p") {
            std::string fmt;
            in >> fmt >> nvars >> declared_clauses;
            if (fmt != "cnf" || nvars <= 0) return false;
        } else {
            Clause c;
            int lit = std::stoi(tok);
            while (lit != 0) {
                if (lit == 0 || std::abs(lit) > nvars) return false;
                c.push_back(lit);
                if (!(in >> lit)) return false;
            }
            clauses.push_back(std::move(c));
        }
    }
    return nvars > 0 && (declared_clauses < 0 || declared_clauses == (int)clauses.size());
}

static bool clause_satisfied(const Clause& c, const std::vector<uint8_t>& assign) {
    for (int lit : c) {
        int v = std::abs(lit);
        bool val = assign[v] != 0;
        if ((lit > 0 && val) || (lit < 0 && !val)) return true;
    }
    return false;
}

static Row make_row(int nvars, const std::array<int, 3>& vars, int rhs) {
    Row r((nvars + 1 + 63) / 64, 0);
    for (int v : vars) flip_bit(r, v - 1);
    if (rhs) flip_bit(r, nvars);
    return r;
}

static bool solve_with_free_bits(
    const std::vector<Row>& basis,
    const std::vector<int>& free_vars,
    uint64_t free_mask,
    int nvars,
    std::vector<uint8_t>& assign
) {
    assign.assign(nvars + 1, 0);
    for (size_t i = 0; i < free_vars.size(); ++i) {
        if ((free_mask >> i) & 1ULL) assign[free_vars[i] + 1] = 1;
    }

    for (int p = nvars - 1; p >= 0; --p) {
        if (basis[p].empty()) continue;
        bool val = get_bit(basis[p], nvars);
        for (int b = p + 1; b < nvars; ++b) {
            if (get_bit(basis[p], b) && assign[b + 1]) val = !val;
        }
        assign[p + 1] = val ? 1 : 0;
    }
    return true;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cerr << "usage: solver <formula.cnf> <out.pbp>\n";
        return 1;
    }

    int nvars = 0;
    std::vector<Clause> clauses;
    if (!parse_dimacs(argv[1], nvars, clauses)) {
        std::cout << "c parse failed\ns UNKNOWN\n";
        return 0;
    }

    std::map<std::array<int, 3>, std::vector<std::array<int, 3>>> ternary_groups;
    for (const Clause& c : clauses) {
        if (c.size() != 3) continue;
        std::array<int, 3> key{std::abs(c[0]), std::abs(c[1]), std::abs(c[2])};
        std::sort(key.begin(), key.end());
        if (key[0] == key[1] || key[1] == key[2]) continue;

        std::array<int, 3> lits{c[0], c[1], c[2]};
        ternary_groups[key].push_back(lits);
    }

    const int words = (nvars + 1 + 63) / 64;
    std::vector<Row> basis(nvars);
    int equations = 0;
    int recognized = 0;
    bool inconsistent = false;

    for (const auto& [vars, group] : ternary_groups) {
        if (group.size() < 3 || group.size() > 4) continue;

        int forbidden_parity = -1;
        bool ok = true;
        for (const auto& lits : group) {
            int parity = 0;
            for (int v : vars) {
                int sign = 0;
                for (int lit : lits) {
                    if (std::abs(lit) == v) {
                        sign = lit > 0 ? 1 : -1;
                        break;
                    }
                }
                if (sign == 0) {
                    ok = false;
                    break;
                }
                if (sign < 0) parity ^= 1; // false assignment for a negative literal is true.
            }
            if (!ok) break;
            if (forbidden_parity < 0) forbidden_parity = parity;
            else if (forbidden_parity != parity) ok = false;
        }
        if (!ok || forbidden_parity < 0) continue;

        ++recognized;
        ++equations;
        Row row = make_row(nvars, vars, 1 ^ forbidden_parity);
        if ((int)row.size() != words) {
            std::cout << "c internal row size mismatch\ns UNKNOWN\n";
            return 0;
        }

        while (true) {
            int pivot = first_coeff_bit(row, nvars);
            if (pivot < 0) {
                if (get_bit(row, nvars)) inconsistent = true;
                break;
            }
            if (basis[pivot].empty()) {
                basis[pivot] = std::move(row);
                break;
            }
            xor_row(row, basis[pivot]);
        }
        if (inconsistent) break;
    }

    int rank = 0;
    std::vector<int> free_vars;
    for (int i = 0; i < nvars; ++i) {
        if (basis[i].empty()) free_vars.push_back(i);
        else ++rank;
    }

    std::cout << "c parsed n=" << nvars << " m=" << clauses.size()
              << " ternary_groups=" << ternary_groups.size()
              << " parity_equations=" << equations
              << " recognized=" << recognized
              << " rank=" << rank
              << " free=" << free_vars.size() << "\n";

    if (inconsistent || equations == 0 || free_vars.size() > 24) {
        std::cout << "s UNKNOWN\n";
        return 0;
    }

    std::vector<uint8_t> assign;
    const uint64_t limit = 1ULL << free_vars.size();
    for (uint64_t mask = 0; mask < limit; ++mask) {
        solve_with_free_bits(basis, free_vars, mask, nvars, assign);
        bool ok = true;
        for (const Clause& c : clauses) {
            if (!clause_satisfied(c, assign)) {
                ok = false;
                break;
            }
        }
        if (!ok) continue;

        std::cout << "s SATISFIABLE\n";
        std::cout << "v";
        for (int v = 1; v <= nvars; ++v) {
            std::cout << ' ' << (assign[v] ? v : -v);
            if (v % 20 == 0 && v != nvars) std::cout << "\nv";
        }
        std::cout << " 0\n";
        return 10;
    }

    std::cout << "s UNKNOWN\n";
    return 0;
}
