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

using std::int8_t;
using u64 = unsigned long long;
using u128 = unsigned __int128;
using i128 = __int128_t;

struct Formula {
    int vars = 0;
    std::vector<std::vector<int>> clauses;
    std::vector<std::vector<int>> occ;
};

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

static bool parse_dimacs(const char* path, Formula& f) {
    std::ifstream in(path);
    if (!in) return false;
    std::string tok;
    while (in >> tok) {
        if (tok == "c") {
            std::string rest;
            std::getline(in, rest);
        } else if (tok == "p") {
            std::string cnf;
            int m;
            in >> cnf >> f.vars >> m;
            f.clauses.reserve(m);
        } else {
            int lit = std::stoi(tok);
            std::vector<int> c;
            while (lit != 0) {
                c.push_back(lit);
                if (!(in >> lit)) return false;
            }
            if (c.empty()) return false;
            f.clauses.push_back(std::move(c));
        }
    }
    f.occ.assign(2 * f.vars + 2, {});
    for (int i = 0; i < (int)f.clauses.size(); ++i) {
        for (int lit : f.clauses[i]) {
            int v = lit < 0 ? -lit : lit;
            if (v <= 0 || v > f.vars) return false;
            f.occ[lit_index(lit)].push_back(i);
        }
    }
    return true;
}

static u64 mul_mod(u64 a, u64 b, u64 mod) {
    return (u64)((u128)a * (u128)b % (u128)mod);
}

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

static u64 gcd_u64(u64 a, u64 b) {
    while (b) {
        u64 t = a % b;
        a = b;
        b = t;
    }
    return a;
}

static bool inv_mod(u64 a, u64 mod, u64& inv) {
    i128 t = 0, newt = 1;
    i128 r = (i128)mod, newr = (i128)a;
    while (newr != 0) {
        i128 q = r / newr;
        i128 nt = t - q * newt;
        t = newt;
        newt = nt;
        i128 nr = r - q * newr;
        r = newr;
        newr = nr;
    }
    if (r != 1) return false;
    if (t < 0) t += (i128)mod;
    inv = (u64)t;
    return true;
}

static u64 ceil_sqrt_u64(u64 x) {
    u64 r = 0;
    while ((r + 1) <= x / (r + 1)) ++r;
    return r * r == x ? r : r + 1;
}

static bool bsgs(u64 a, u64 r, u64 n, int k, u64& ans) {
    if (n == 0) return false;
    u64 bound = (k == 64) ? 0 : (1ULL << k);
    if (bound == 0) return false;
    a %= n;
    r %= n;
    u64 m = ceil_sqrt_u64(bound);
    std::unordered_map<u64, unsigned> baby;
    baby.reserve((size_t)m * 2);
    u64 cur = 1 % n;
    for (unsigned j = 0; j < m; ++j) {
        baby.emplace(cur, j);
        cur = mul_mod(cur, a, n);
    }
    u64 am = pow_mod(a, m, n);
    u64 inv_am;
    if (!inv_mod(am, n, inv_am)) return false;
    u64 gamma = r;
    u64 rounds = (bound + m - 1) / m + 1;
    for (u64 i = 0; i < rounds; ++i) {
        auto it = baby.find(gamma);
        if (it != baby.end()) {
            u64 cand = i * m + it->second;
            if (cand < bound && pow_mod(a, cand, n) == r) {
                ans = cand;
                return true;
            }
        }
        gamma = mul_mod(gamma, inv_am, n);
    }
    return false;
}

static bool has_abs(const std::vector<int>& c, int v) {
    for (int lit : c) {
        if ((lit < 0 ? -lit : lit) == v) return true;
    }
    return false;
}

static bool set_val(std::vector<int8_t>& val, int v, bool b) {
    int8_t x = b ? 1 : 0;
    if (val[v] != -1) return val[v] == x;
    val[v] = x;
    return true;
}

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

static bool propagate(const Formula& f, std::vector<int8_t>& val) {
    std::vector<int> queue;
    queue.reserve(f.vars);
    for (int v = 1; v <= f.vars; ++v) {
        if (val[v] != -1) queue.push_back(val[v] ? v : -v);
    }
    size_t head = 0;
    while (head < queue.size()) {
        int lit = queue[head++];
        int false_lit = -lit;
        for (int ci : f.occ[lit_index(false_lit)]) {
            const auto& c = f.clauses[ci];
            bool sat = false;
            int unknown_count = 0;
            int last_unknown = 0;
            for (int l : c) {
                int lv = lit_value(val, l);
                if (lv == 1) {
                    sat = true;
                    break;
                }
                if (lv < 0) {
                    ++unknown_count;
                    last_unknown = l;
                }
            }
            if (sat) continue;
            if (unknown_count == 0) return false;
            if (unknown_count == 1) {
                int v = last_unknown < 0 ? -last_unknown : last_unknown;
                bool b = last_unknown > 0;
                if (val[v] != -1) {
                    if (val[v] != (b ? 1 : 0)) return false;
                } else {
                    val[v] = b ? 1 : 0;
                    queue.push_back(last_unknown);
                }
            }
        }
    }
    return true;
}

static bool clause_check(const Formula& f, const std::vector<int8_t>& val) {
    for (const auto& c : f.clauses) {
        bool sat = false;
        for (int lit : c) {
            int v = lit < 0 ? -lit : lit;
            bool b = val[v] == 1;
            if ((lit > 0 && b) || (lit < 0 && !b)) {
                sat = true;
                break;
            }
        }
        if (!sat) 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;
    }

    Formula f;
    if (!parse_dimacs(argv[1], f) || f.vars <= 0 || f.clauses.empty()) {
        std::printf("c parse or empty-formula failure\ns UNKNOWN\n");
        return 0;
    }

    std::vector<std::vector<int>> first;
    for (const auto& c : f.clauses) {
        if (has_abs(c, 2)) break;
        first.push_back(c);
    }
    if (first.empty() || first.size() % 2 != 0 || first[0].size() != 2 || !has_abs(first[0], 1)) {
        std::printf("c detector failed at initial selector\ns UNKNOWN\n");
        return 0;
    }
    int other = (first[0][0] == 1 || first[0][0] == -1) ? first[0][1] : first[0][0];
    int k = (other < 0 ? -other : other) - 1;
    int w = (int)first.size() / 2;
    if (k <= 0 || k > 63 || w <= 0 || w > 64 || k + w > f.vars) {
        std::printf("c unsupported dimensions k=%d w=%d\ns UNKNOWN\n", k, w);
        return 0;
    }

    u64 a = 0;
    for (int j = 0; j < w; ++j) {
        const auto& c = first[w + j];
        int lit = 0;
        for (int l : c) {
            if ((l < 0 ? -l : l) != 1) lit = l;
        }
        if (lit > 0) a |= (1ULL << j);
    }

    int idx = (int)f.clauses.size() - 1;
    std::vector<int> tail;
    while (idx >= 0 && f.clauses[idx].size() == 1) {
        tail.push_back(f.clauses[idx][0]);
        --idx;
    }
    std::reverse(tail.begin(), tail.end());
    if ((int)tail.size() < w) {
        std::printf("c detector failed at final unit target\ns UNKNOWN\n");
        return 0;
    }
    if ((int)tail.size() > w) tail.erase(tail.begin(), tail.end() - w);
    u64 r = 0;
    for (int j = 0; j < w; ++j) {
        if (tail[j] > 0) r |= (1ULL << j);
    }

    int start_sel = idx - 2 * w + 1;
    if (start_sel < 0) {
        std::printf("c detector failed at final selector position\ns UNKNOWN\n");
        return 0;
    }
    std::vector<int> plast(w);
    for (int j = 0; j < w; ++j) {
        const auto& c1 = f.clauses[start_sel + 2 * j];
        const auto& c2 = f.clauses[start_sel + 2 * j + 1];
        int tv = tail[j] < 0 ? -tail[j] : tail[j];
        int found = 0;
        for (int lit : c1) {
            int v = lit < 0 ? -lit : lit;
            if (v != k && v != tv) found = v;
        }
        for (int lit : c2) {
            int v = lit < 0 ? -lit : lit;
            if (v != k && v != tv) found = v;
        }
        if (!found) {
            std::printf("c detector failed extracting final product bit\ns UNKNOWN\n");
            return 0;
        }
        plast[j] = found;
    }

    int longidx = -1;
    for (int i = 0; i < start_sel; ++i) {
        if (f.clauses[i].size() > 4) longidx = i;
    }
    if (longidx < 0) {
        std::printf("c detector failed finding comparator\ns UNKNOWN\n");
        return 0;
    }
    std::vector<char> event(f.vars + 1, 0);
    for (int lit : f.clauses[longidx]) event[lit < 0 ? -lit : lit] = 1;
    std::vector<int> nbits(w, -1);
    nbits[0] = 1;
    int begin = std::max(0, longidx - 10 * w - 100);
    for (int j = 0; j < w; ++j) {
        int pv = plast[j];
        for (int i = begin; i < longidx; ++i) {
            const auto& c = f.clauses[i];
            if (c.size() != 2 || !has_abs(c, pv)) continue;
            int other_lit = (std::abs(c[0]) == pv) ? c[1] : c[0];
            int p_lit = (std::abs(c[0]) == pv) ? c[0] : c[1];
            int ov = other_lit < 0 ? -other_lit : other_lit;
            if (!event[ov]) nbits[j] = p_lit > 0 ? 1 : 0;
        }
    }
    u64 n = 0;
    for (int j = 0; j < w; ++j) {
        if (nbits[j] < 0) {
            std::printf("c detector failed extracting modulus bit %d\ns UNKNOWN\n", j);
            return 0;
        }
        if (nbits[j]) n |= (1ULL << j);
    }
    if (n == 0 || a >= n || r >= n || gcd_u64(a, n) != 1) {
        std::printf("c unsupported modular parameters k=%d w=%d a=%llu n=%llu r=%llu\ns UNKNOWN\n",
                    k, w, a, n, r);
        return 0;
    }

    u64 x = 0;
    if (!bsgs(a, r, n, k, x)) {
        std::printf("c bounded discrete log not found k=%d w=%d a=%llu n=%llu r=%llu\ns UNKNOWN\n",
                    k, w, a, n, r);
        return 0;
    }

    std::vector<std::vector<int>> S(k + 1), P(k + 1);
    S[1].resize(w);
    for (int j = 0; j < w; ++j) S[1][j] = k + 1 + j;

    for (int v = 2; v <= k; ++v) {
        const auto& pos = f.occ[lit_index(v)];
        const auto& neg = f.occ[lit_index(-v)];
        if ((int)pos.size() < 2 * w || (int)neg.size() < 2 * w) {
            std::printf("c selector occurrence mismatch for exponent bit %d\ns UNKNOWN\n", v);
            return 0;
        }
        std::vector<char> prevmark(f.vars + 1, 0);
        for (int pv : S[v - 1]) prevmark[pv] = 1;
        S[v].resize(w);
        P[v].resize(w);
        for (int j = 0; j < w; ++j) {
            int out = 0;
            for (int ci : {pos[2 * j], pos[2 * j + 1]}) {
                for (int lit : f.clauses[ci]) {
                    int av = lit < 0 ? -lit : lit;
                    if (av != v && !prevmark[av]) out = av;
                }
            }
            if (!out) {
                std::printf("c failed extracting state vector at bit %d\ns UNKNOWN\n", v);
                return 0;
            }
            S[v][j] = out;
            int prod = 0;
            for (int ci : {neg[2 * j], neg[2 * j + 1]}) {
                for (int lit : f.clauses[ci]) {
                    int av = lit < 0 ? -lit : lit;
                    if (av != v && av != out) prod = av;
                }
            }
            if (!prod) {
                std::printf("c failed extracting product vector at bit %d\ns UNKNOWN\n", v);
                return 0;
            }
            P[v][j] = prod;
        }
    }

    std::vector<int8_t> val(f.vars + 1, -1);
    for (int i = 1; i <= k; ++i) {
        if (!set_val(val, i, ((x >> (i - 1)) & 1ULL) != 0)) {
            std::printf("c exponent assignment conflict\ns UNKNOWN\n");
            return 0;
        }
    }
    for (const auto& c : f.clauses) {
        if (c.size() == 1) {
            int lit = c[0];
            if (!set_val(val, lit < 0 ? -lit : lit, lit > 0)) {
                std::printf("c unit assignment conflict\ns UNKNOWN\n");
                return 0;
            }
        }
    }

    u64 state = (x & 1ULL) ? a : 1ULL;
    for (int j = 0; j < w; ++j) {
        if (!set_val(val, S[1][j], ((state >> j) & 1ULL) != 0)) {
            std::printf("c initial state conflict\ns UNKNOWN\n");
            return 0;
        }
    }
    u64 power = a;
    for (int i = 2; i <= k; ++i) {
        power = mul_mod(power, power, n);
        u64 prod = mul_mod(state, power, n);
        for (int j = 0; j < w; ++j) {
            if (!set_val(val, P[i][j], ((prod >> j) & 1ULL) != 0)) {
                std::printf("c product vector conflict\ns UNKNOWN\n");
                return 0;
            }
        }
        if ((x >> (i - 1)) & 1ULL) state = prod;
        for (int j = 0; j < w; ++j) {
            if (!set_val(val, S[i][j], ((state >> j) & 1ULL) != 0)) {
                std::printf("c state vector conflict\ns UNKNOWN\n");
                return 0;
            }
        }
    }
    if (state != r) {
        std::printf("c recovered exponent failed final arithmetic check\ns UNKNOWN\n");
        return 0;
    }

    if (!propagate(f, val)) {
        std::printf("c propagation conflict after high-level assignment\ns UNKNOWN\n");
        return 0;
    }
    for (int v = 1; v <= f.vars; ++v) {
        if (val[v] == -1) val[v] = 0;
    }
    if (!clause_check(f, val)) {
        std::printf("c final CNF model check failed\ns UNKNOWN\n");
        return 0;
    }

    std::printf("c recovered dislog structure k=%d w=%d a=%llu n=%llu r=%llu x=%llu\n",
                k, w, a, n, r, x);
    std::printf("s SATISFIABLE\n");
    int per_line = 0;
    std::printf("v");
    for (int v = 1; v <= f.vars; ++v) {
        if (per_line >= 1000) {
            std::printf("\nv");
            per_line = 0;
        }
        std::printf(" %d", val[v] ? v : -v);
        ++per_line;
    }
    std::printf(" 0\n");
    return 10;
}
