#include <algorithm>
#include <array>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <numeric>
#include <string>
#include <tuple>
#include <unordered_map>
#include <vector>

using u128 = unsigned __int128;

struct Clause {
    std::vector<int> lits;
};

struct Gate {
    int out = 0;
    std::vector<int> inputs;
    int table[8] = {0, 0, 0, 0, 0, 0, 0, 0};
};

struct Group {
    int a = 0, b = 0, c = 0;
    std::vector<std::array<int, 3>> clauses;
};

static int lit_value(int lit, const std::vector<int>& val) {
    int v = val[std::abs(lit)];
    if (v < 0) return -1;
    return lit > 0 ? v : 1 - v;
}

static bool clause_satisfied(const Clause& cl, const std::vector<int>& val) {
    for (int lit : cl.lits) {
        int v = lit_value(lit, val);
        if (v == 1) return true;
    }
    return false;
}

static int bitlen(u128 x) {
    int n = 0;
    while (x) {
        ++n;
        x >>= 1;
    }
    return n;
}

static u128 gcd128(u128 a, u128 b) {
    while (b != 0) {
        u128 r = a % b;
        a = b;
        b = r;
    }
    return a;
}

static u128 mul_mod(u128 a, u128 b, u128 mod) {
    u128 res = 0;
    a %= mod;
    while (b) {
        if (b & 1) res = (res >= mod - a) ? (res - (mod - a)) : (res + a);
        b >>= 1;
        if (b) a = (a >= mod - a) ? (a - (mod - a)) : (a + a);
    }
    return res;
}

static u128 pow_mod(u128 a, u128 e, u128 mod) {
    u128 r = 1 % mod;
    while (e) {
        if (e & 1) r = mul_mod(r, a, mod);
        e >>= 1;
        if (e) a = mul_mod(a, a, mod);
    }
    return r;
}

static bool is_prime(u128 n) {
    if (n < 2) return false;
    static const uint64_t small[] = {2,3,5,7,11,13,17,19,23,29,31,37};
    for (uint64_t p : small) {
        if (n % p == 0) return n == p;
    }
    u128 d = n - 1;
    int s = 0;
    while ((d & 1) == 0) {
        d >>= 1;
        ++s;
    }
    static const uint64_t bases[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
    for (uint64_t aa : bases) {
        if (u128(aa) % n == 0) continue;
        u128 x = pow_mod(aa, d, n);
        if (x == 1 || x == n - 1) continue;
        bool comp = true;
        for (int r = 1; r < s; ++r) {
            x = mul_mod(x, x, n);
            if (x == n - 1) {
                comp = false;
                break;
            }
        }
        if (comp) return false;
    }
    return true;
}

static u128 rho(u128 n) {
    if ((n & 1) == 0) return 2;
    if (n % 3 == 0) return 3;
    uint64_t seed = 1;
    while (true) {
        u128 c = 2 * seed + 1;
        u128 x = 5 + seed;
        u128 y = x;
        u128 d = 1;
        for (int iter = 0; d == 1 && iter < 200000; ++iter) {
            x = (mul_mod(x, x, n) + c) % n;
            y = (mul_mod(y, y, n) + c) % n;
            y = (mul_mod(y, y, n) + c) % n;
            u128 diff = x > y ? x - y : y - x;
            d = gcd128(diff, n);
        }
        if (d > 1 && d < n) return d;
        ++seed;
    }
}

static void factor_rec(u128 n, std::vector<u128>& out) {
    if (n == 1) return;
    if (is_prime(n)) {
        out.push_back(n);
        return;
    }
    u128 d = rho(n);
    factor_rec(d, out);
    factor_rec(n / d, out);
}

static std::string to_string128(u128 x) {
    if (x == 0) return "0";
    std::string s;
    while (x) {
        int d = int(x % 10);
        s.push_back(char('0' + d));
        x /= 10;
    }
    std::reverse(s.begin(), s.end());
    return s;
}

static void gen_divisors_rec(const std::vector<std::pair<u128,int>>& pf, int idx, u128 cur,
                             std::vector<u128>& divs) {
    if (idx == (int)pf.size()) {
        divs.push_back(cur);
        return;
    }
    u128 v = 1;
    for (int i = 0; i <= pf[idx].second; ++i) {
        gen_divisors_rec(pf, idx + 1, cur * v, divs);
        v *= pf[idx].first;
    }
}

static bool derive_gate(const Group& g, const std::vector<int>& inputs, Gate& gate) {
    gate.out = g.c;
    gate.inputs = inputs;
    int k = (int)inputs.size();
    if (k < 1 || k > 3) return false;
    for (int mask = 0; mask < (1 << k); ++mask) {
        bool allowed[2] = {true, true};
        for (int z = 0; z <= 1; ++z) {
            for (const auto& cl : g.clauses) {
                bool sat = false;
                for (int lit : cl) {
                    int av = std::abs(lit);
                    int bit = z;
                    if (av != g.c) {
                        auto it = std::find(inputs.begin(), inputs.end(), av);
                        if (it == inputs.end()) return false;
                        int pos = (int)(it - inputs.begin());
                        bit = (mask >> pos) & 1;
                    }
                    if (lit < 0) bit = 1 - bit;
                    sat |= bit != 0;
                }
                if (!sat) {
                    allowed[z] = false;
                    break;
                }
            }
        }
        if (allowed[0]) gate.table[mask] = 0;
        else if (allowed[1]) gate.table[mask] = 1;
        else return false;
    }
    return true;
}

static bool evaluate_candidate(u128 left, u128 right, int left_bits, int right_bits,
                               int nvars, const std::vector<Gate>& gates,
                               const std::vector<Clause>& clauses,
                               std::vector<int>& val) {
    val.assign(nvars + 1, 0);
    for (int i = 0; i < left_bits; ++i) val[1 + i] = int((left >> i) & 1);
    for (int i = 0; i < right_bits; ++i) val[1 + left_bits + i] = int((right >> i) & 1);
    for (const Gate& g : gates) {
        int idx = 0;
        for (int i = 0; i < (int)g.inputs.size(); ++i) idx |= (val[g.inputs[i]] << i);
        val[g.out] = g.table[idx];
    }
    for (const Clause& cl : clauses) {
        if (!clause_satisfied(cl, val)) return false;
    }
    return true;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    (void)argv[2];
    std::ifstream in(argv[1]);
    if (!in) return 1;

    int nvars = 0, declared_clauses = 0;
    std::vector<Clause> clauses;
    std::vector<int> units;
    std::unordered_map<int, int> group_index;
    std::vector<Group> groups;
    std::array<int,3> first_ternary = {0,0,0};
    bool have_first_ternary = false;

    std::string tok;
    while (in >> tok) {
        if (tok == "p") {
            std::string cnf;
            in >> cnf >> nvars >> declared_clauses;
            continue;
        }
        int lit = std::stoi(tok);
        Clause cl;
        while (lit != 0) {
            cl.lits.push_back(lit);
            in >> lit;
        }
        if (cl.lits.empty()) {
            std::printf("s UNKNOWN\n");
            return 0;
        }
        if ((int)cl.lits.size() == 1) units.push_back(cl.lits[0]);
        if ((int)cl.lits.size() == 3) {
            std::array<int,3> raw = {cl.lits[0], cl.lits[1], cl.lits[2]};
            if (!have_first_ternary) {
                first_ternary = raw;
                have_first_ternary = true;
            }
            int a = std::abs(raw[0]), b = std::abs(raw[1]), c = std::abs(raw[2]);
            int out = std::max(a, std::max(b, c));
            auto it = group_index.find(out);
            if (it == group_index.end()) {
                int idx = (int)groups.size();
                group_index[out] = idx;
                Group g;
                g.c = out;
                groups.push_back(g);
                it = group_index.find(out);
            }
            groups[it->second].clauses.push_back(raw);
        } else if ((int)cl.lits.size() != 1) {
            std::printf("c unsupported clause width\n");
            std::printf("s UNKNOWN\n");
            return 0;
        }
        clauses.push_back(std::move(cl));
    }

    if (!have_first_ternary || units.empty() || nvars <= 0) {
        std::printf("s UNKNOWN\n");
        return 0;
    }

    std::vector<char> is_output(nvars + 1, 0);
    std::vector<Gate> gates;
    gates.reserve(groups.size());
    for (const Group& g : groups) {
        if ((int)g.clauses.size() != 4) {
            std::printf("c unsupported ternary group size\n");
            std::printf("s UNKNOWN\n");
            return 0;
        }
        std::vector<int> inputs;
        for (const auto& cl : g.clauses) {
            for (int lit : cl) {
                int v = std::abs(lit);
                if (v != g.c && std::find(inputs.begin(), inputs.end(), v) == inputs.end()) {
                    inputs.push_back(v);
                }
            }
        }
        if (inputs.size() < 2 || inputs.size() > 3) {
            std::printf("c unsupported gate fanin\n");
            std::printf("s UNKNOWN\n");
            return 0;
        }
        std::sort(inputs.begin(), inputs.end());
        Gate gate;
        if (!derive_gate(g, inputs, gate)) {
            std::printf("c non-functional gate group\n");
            std::printf("s UNKNOWN\n");
            return 0;
        }
        if (gate.out > nvars || is_output[gate.out]) {
            std::printf("c bad gate topology\n");
            std::printf("s UNKNOWN\n");
            return 0;
        }
        is_output[gate.out] = 1;
        gates.push_back(gate);
    }
    std::sort(gates.begin(), gates.end(), [](const Gate& x, const Gate& y) {
        return x.out < y.out;
    });
    int total_input_bits = gates.empty() ? 0 : gates.front().out - 1;
    int left_bits = std::abs(first_ternary[1]) - 1;
    int right_bits = total_input_bits - left_bits;
    if (left_bits <= 0 || right_bits <= 0 || (int)units.size() >= 127 || total_input_bits <= 0) {
        std::printf("c unsupported recovered dimensions\n");
        std::printf("s UNKNOWN\n");
        return 0;
    }
    if ((int)gates.size() + total_input_bits != nvars) {
        std::printf("c input/output count mismatch\n");
        std::printf("s UNKNOWN\n");
        return 0;
    }
    for (int v = 1; v <= total_input_bits; ++v) {
        if (is_output[v]) {
            std::printf("c primary input prefix mismatch\n");
            std::printf("s UNKNOWN\n");
            return 0;
        }
    }

    u128 target = 0;
    for (int i = 0; i < (int)units.size(); ++i) {
        if (units[i] > 0) target |= (u128(1) << i);
    }
    std::printf("c recovered multiplier widths %d x %d and product %s\n",
                left_bits, right_bits, to_string128(target).c_str());

    std::vector<u128> prime_list;
    factor_rec(target, prime_list);
    std::sort(prime_list.begin(), prime_list.end());
    std::vector<std::pair<u128,int>> pf;
    for (u128 p : prime_list) {
        if (pf.empty() || pf.back().first != p) pf.push_back({p, 1});
        else pf.back().second++;
    }
    std::vector<u128> divs;
    gen_divisors_rec(pf, 0, 1, divs);
    std::sort(divs.begin(), divs.end());

    std::vector<int> model;
    for (u128 d : divs) {
        if (d == 0 || target % d != 0) continue;
        u128 q = target / d;
        if (bitlen(d) <= left_bits && bitlen(q) <= right_bits) {
            if (evaluate_candidate(d, q, left_bits, right_bits, nvars, gates, clauses, model)) {
                std::printf("c selected factors %s and %s\n", to_string128(d).c_str(), to_string128(q).c_str());
                std::printf("s SATISFIABLE\n");
                std::printf("v");
                for (int v = 1; v <= nvars; ++v) {
                    std::printf(" %d", model[v] ? v : -v);
                    if (v % 20 == 0 && v != nvars) std::printf("\nv");
                }
                std::printf(" 0\n");
                return 10;
            }
        }
        if (bitlen(d) <= right_bits && bitlen(q) <= left_bits) {
            if (evaluate_candidate(q, d, left_bits, right_bits, nvars, gates, clauses, model)) {
                std::printf("c selected factors %s and %s\n", to_string128(q).c_str(), to_string128(d).c_str());
                std::printf("s SATISFIABLE\n");
                std::printf("v");
                for (int v = 1; v <= nvars; ++v) {
                    std::printf(" %d", model[v] ? v : -v);
                    if (v % 20 == 0 && v != nvars) std::printf("\nv");
                }
                std::printf(" 0\n");
                return 10;
            }
        }
    }

    std::printf("c no factor split produced a verified CNF model\n");
    std::printf("s UNKNOWN\n");
    return 0;
}
