#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <numeric>
#include <queue>
#include <random>
#include <sstream>
#include <string>
#include <unordered_set>
#include <vector>

using u64 = std::uint64_t;
using u128 = unsigned __int128;

struct Formula {
    int nvars = 0;
    int nclauses_declared = 0;
    std::vector<std::vector<int>> clauses;
};

static u64 lit_key(int lit, int nvars) {
    return static_cast<u64>(lit + nvars + 1);
}

static u64 pair_key(int a, int b, int nvars) {
    u64 x = lit_key(a, nvars), y = lit_key(b, nvars);
    if (x > y) std::swap(x, y);
    return (x << 32) | y;
}

static Formula read_dimacs(const char* path) {
    std::ifstream in(path);
    Formula f;
    std::string line;
    while (std::getline(in, line)) {
        if (line.empty() || line[0] == 'c') continue;
        if (line[0] == 'p') {
            std::istringstream iss(line);
            std::string p, cnf;
            iss >> p >> cnf >> f.nvars >> f.nclauses_declared;
            continue;
        }
        std::istringstream iss(line);
        std::vector<int> clause;
        int lit;
        while (iss >> lit) {
            if (lit == 0) break;
            clause.push_back(lit);
        }
        if (!clause.empty()) f.clauses.push_back(std::move(clause));
    }
    return f;
}

static bool detect_input_blocks(const Formula& f, int& k) {
    std::vector<std::vector<int>> longs;
    for (const auto& c : f.clauses) {
        if (c.size() > 10) longs.push_back(c);
    }
    if (longs.size() != 2 || longs[0].size() != longs[1].size()) return false;
    k = static_cast<int>(longs[0].size());
    if (k < 2 || 2 * k > f.nvars) return false;
    for (int i = 0; i < k; ++i) {
        if (longs[0][i] != -(i + 1)) return false;
        if (longs[1][i] != -(k + i + 1)) return false;
    }
    return true;
}

static bool recover_constant(const Formula& f, int k, u64& N, int& source_start, int& source_end) {
    if (k - 1 <= 0 || k - 1 > 63) return false;

    source_end = 0;
    int lo = std::max<int>(0, static_cast<int>(f.clauses.size()) - 80);
    for (int i = static_cast<int>(f.clauses.size()) - 2; i >= lo; --i) {
        const auto& a = f.clauses[i];
        const auto& b = f.clauses[i + 1];
        if (a.size() != 2 || b.size() != 2) continue;
        if (a[0] < 0 && a[1] < 0) {
            int x = -a[0], y = -a[1];
            if ((b[0] == x && b[1] == y) || (b[0] == y && b[1] == x)) {
                source_end = std::min(x, y);
                break;
            }
        }
    }
    if (source_end <= 0) return false;
    source_start = source_end - 2 * (k - 2);
    if (source_start <= 0) return false;

    std::unordered_set<u64> binaries;
    binaries.reserve(f.clauses.size() * 2);
    for (const auto& c : f.clauses) {
        if (c.size() == 2) binaries.insert(pair_key(c[0], c[1], f.nvars));
    }

    N = 1;  // The encoded product is odd; bit 0 is handled specially by PEQNP.
    for (int bit = 1; bit < k - 1; ++bit) {
        int s = source_start + 2 * bit;
        bool has_direct_equiv = false;
        for (int a = source_end + 1; a <= f.nvars; ++a) {
            if (binaries.count(pair_key(-s, a, f.nvars)) &&
                binaries.count(pair_key(s, -a, f.nvars))) {
                has_direct_equiv = true;
                break;
            }
        }
        if (!has_direct_equiv) N |= (u64(1) << bit);
    }
    return N > 1 && (N & 1);
}

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

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

static bool is_prime_u64(u64 n) {
    if (n < 2) return false;
    static const u64 small[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
    for (u64 p : small) {
        if (n % p == 0) return n == p;
    }
    u64 d = n - 1, s = 0;
    while ((d & 1) == 0) {
        d >>= 1;
        ++s;
    }
    static const u64 bases[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
    for (u64 a : bases) {
        if (a % n == 0) continue;
        u64 x = pow_mod(a % n, d, n);
        if (x == 1 || x == n - 1) continue;
        bool witness = true;
        for (u64 r = 1; r < s; ++r) {
            x = mul_mod(x, x, n);
            if (x == n - 1) {
                witness = false;
                break;
            }
        }
        if (witness) return false;
    }
    return true;
}

static u64 pollard_rho(u64 n) {
    if ((n & 1) == 0) return 2;
    if (n % 3 == 0) return 3;
    for (u64 c = 1; c < 200; ++c) {
        u64 x = 2, y = 2, d = 1;
        auto f = [&](u64 v) { return (mul_mod(v, v, n) + c) % n; };
        for (int iter = 0; d == 1 && iter < 200000; ++iter) {
            x = f(x);
            y = f(f(y));
            u64 diff = x > y ? x - y : y - x;
            d = std::gcd(diff, n);
        }
        if (d > 1 && d < n) return d;
    }
    return 0;
}

static bool find_factor_pair(u64 N, u64& u, u64& v) {
    if (N < 4 || is_prime_u64(N)) return false;
    u64 d = 0;
    for (u64 p : {3ULL, 5ULL, 7ULL, 11ULL, 13ULL, 17ULL, 19ULL, 23ULL, 29ULL, 31ULL, 37ULL}) {
        if (N % p == 0) {
            d = p;
            break;
        }
    }
    if (!d) d = pollard_rho(N);
    if (!d || d == N) return false;
    u = d;
    v = N / d;
    if (u > v) std::swap(u, v);
    return u > 1 && v > 1 && u * (u128)v == N;
}

static bool assign_lit(std::vector<int>& val, int lit) {
    int v = std::abs(lit);
    int want = lit > 0 ? 1 : -1;
    if (val[v] != 0) return val[v] == want;
    val[v] = want;
    return true;
}

static bool unit_propagate_and_validate(const Formula& f, std::vector<int>& val) {
    bool changed = true;
    while (changed) {
        changed = false;
        for (const auto& c : f.clauses) {
            bool satisfied = false;
            int unassigned = 0;
            int unit = 0;
            for (int lit : c) {
                int vv = val[std::abs(lit)];
                if (vv == 0) {
                    ++unassigned;
                    unit = lit;
                } else if ((vv == 1) == (lit > 0)) {
                    satisfied = true;
                    break;
                }
            }
            if (satisfied) continue;
            if (unassigned == 0) return false;
            if (unassigned == 1) {
                if (!assign_lit(val, unit)) return false;
                changed = true;
            }
        }
    }
    for (int v = 1; v <= f.nvars; ++v) {
        if (val[v] == 0) val[v] = -1;
    }
    for (const auto& c : f.clauses) {
        bool ok = false;
        for (int lit : c) {
            int vv = val[std::abs(lit)];
            if ((vv == 1) == (lit > 0)) {
                ok = true;
                break;
            }
        }
        if (!ok) 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 = read_dimacs(argv[1]);
    if (f.nvars <= 0 || f.clauses.empty()) {
        std::printf("s UNKNOWN\n");
        return 0;
    }

    int k = 0;
    u64 N = 0;
    int source_start = 0, source_end = 0;
    if (!detect_input_blocks(f, k) || !recover_constant(f, k, N, source_start, source_end)) {
        std::printf("c unsupported structure\ns UNKNOWN\n");
        return 0;
    }

    u64 u = 0, v = 0;
    if (!find_factor_pair(N, u, v)) {
        std::printf("c recovered N=%llu but no nontrivial factor pair found\n", (unsigned long long)N);
        std::printf("s UNKNOWN\n");
        return 0;
    }
    if (((u + v) & 1) || (v < u)) {
        std::printf("s UNKNOWN\n");
        return 0;
    }
    u64 a = (u + v) / 2;
    u64 b = (v - u) / 2;
    if (k < 64 && (a >= (u64(1) << k) || b >= (u64(1) << k))) {
        std::printf("s UNKNOWN\n");
        return 0;
    }
    if ((u128)a * a < (u128)b * b || (u128)a * a - (u128)b * b != N) {
        std::printf("s UNKNOWN\n");
        return 0;
    }

    std::vector<int> val(f.nvars + 1, 0);
    for (int i = 0; i < k; ++i) {
        if (!assign_lit(val, ((a >> i) & 1) ? (i + 1) : -(i + 1))) {
            std::printf("s UNKNOWN\n");
            return 0;
        }
        int qv = k + i + 1;
        if (!assign_lit(val, ((b >> i) & 1) ? qv : -qv)) {
            std::printf("s UNKNOWN\n");
            return 0;
        }
    }
    if (!unit_propagate_and_validate(f, val)) {
        std::printf("c candidate model failed CNF validation\ns UNKNOWN\n");
        return 0;
    }

    std::printf("c recovered k=%d N=%llu factors=%llu*%llu fermat_a=%llu fermat_b=%llu\n",
                k, (unsigned long long)N, (unsigned long long)u, (unsigned long long)v,
                (unsigned long long)a, (unsigned long long)b);
    std::printf("s SATISFIABLE\n");
    std::printf("v");
    for (int i = 1; i <= f.nvars; ++i) {
        int lit = val[i] == 1 ? i : -i;
        std::printf(" %d", lit);
        if (i % 100 == 0 && i != f.nvars) std::printf("\nv");
    }
    std::printf(" 0\n");
    (void)source_start;
    return 10;
}
