#include <algorithm>
#include <cassert>
#include <chrono>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iostream>
#include <limits>
#include <numeric>
#include <queue>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>

using Clock = std::chrono::steady_clock;

struct Clause {
    std::vector<int> lits;
    int w0 = 0;
    int w1 = 0;
    bool learnt = false;
    double activity = 0.0;
};

static inline int lit_index(int lit) {
    int v = std::abs(lit);
    return (v << 1) ^ (lit < 0);
}

static inline int lit_neg_index(int lit) {
    int v = std::abs(lit);
    return (v << 1) ^ (lit > 0);
}

struct Solver {
    int nvars = 0;
    std::vector<Clause> clauses;
    std::vector<std::vector<int>> watches;
    std::vector<signed char> assigns; // -1 false, 0 undef, +1 true
    std::vector<int> levels;
    std::vector<int> reasons;
    std::vector<int> trail;
    std::vector<int> trail_lim;
    size_t qhead = 0;

    std::vector<double> var_activity;
    double var_inc = 1.0;
    double var_decay = 0.95;
    std::priority_queue<std::pair<double, int>> order_heap;
    std::vector<signed char> phase;

    std::vector<int> seen;
    int seen_token = 1;

    Clock::time_point start_time;
    double time_limit = 590.0;
    long long conflicts = 0;
    long long propagations = 0;
    int restart_limit = 100;
    int learnt_limit = 200000;
    int max_clause_count = 0;

    explicit Solver(int n = 0) { init(n); }

    void init(int n) {
        nvars = n;
        watches.assign((nvars + 1) * 2 + 4, {});
        assigns.assign(nvars + 1, 0);
        levels.assign(nvars + 1, 0);
        reasons.assign(nvars + 1, -1);
        var_activity.assign(nvars + 1, 0.0);
        phase.assign(nvars + 1, -1);
        seen.assign(nvars + 1, 0);
        trail.clear();
        trail_lim.clear();
        qhead = 0;
        while (!order_heap.empty()) order_heap.pop();
    }

    int value_lit(int lit) const {
        int v = std::abs(lit);
        int a = assigns[v];
        if (a == 0) return 0;
        return lit > 0 ? a : -a;
    }

    int decision_level() const { return (int)trail_lim.size(); }

    bool enqueue(int lit, int reason) {
        int v = std::abs(lit);
        int val = lit > 0 ? 1 : -1;
        if (assigns[v] != 0) return assigns[v] == val;
        assigns[v] = (signed char)val;
        levels[v] = decision_level();
        reasons[v] = reason;
        phase[v] = (signed char)val;
        trail.push_back(lit);
        return true;
    }

    void attach_clause(int ci) {
        Clause &c = clauses[ci];
        if (c.lits.size() == 1) {
            return;
        }
        c.w0 = 0;
        c.w1 = 1;
        watches[lit_index(c.lits[c.w0])].push_back(ci);
        watches[lit_index(c.lits[c.w1])].push_back(ci);
    }

    bool add_clause(std::vector<int> lits, bool learnt = false) {
        if (lits.empty()) return false;
        std::sort(lits.begin(), lits.end(), [](int a, int b) {
            return std::abs(a) == std::abs(b) ? a < b : std::abs(a) < std::abs(b);
        });
        std::vector<int> out;
        out.reserve(lits.size());
        int prev = 0;
        for (int lit : lits) {
            if (lit == prev) continue;
            if (lit == -prev) return true;
            out.push_back(lit);
            prev = lit;
        }
        int ci = (int)clauses.size();
        Clause c;
        c.lits = std::move(out);
        c.learnt = learnt;
        clauses.push_back(std::move(c));
        if (clauses[ci].lits.size() == 1) {
            if (!enqueue(clauses[ci].lits[0], ci)) return false;
        } else {
            attach_clause(ci);
        }
        for (int lit : clauses[ci].lits) {
            int v = std::abs(lit);
            var_activity[v] += 1.0;
        }
        return true;
    }

    int propagate() {
        while (qhead < trail.size()) {
            int lit = trail[qhead++];
            int false_idx = lit_neg_index(lit);
            auto &ws = watches[false_idx];
            size_t i = 0;
            while (i < ws.size()) {
                int ci = ws[i];
                Clause &c = clauses[ci];
                int wi = (lit_index(c.lits[c.w0]) == false_idx) ? c.w0 : c.w1;
                int oi = (wi == c.w0) ? c.w1 : c.w0;
                int other = c.lits[oi];
                if (value_lit(other) > 0) {
                    ++i;
                    continue;
                }
                bool found = false;
                for (int k = 0; k < (int)c.lits.size(); ++k) {
                    if (k == c.w0 || k == c.w1) continue;
                    if (value_lit(c.lits[k]) >= 0) {
                        if (wi == c.w0) c.w0 = k;
                        else c.w1 = k;
                        ws[i] = ws.back();
                        ws.pop_back();
                        watches[lit_index(c.lits[k])].push_back(ci);
                        found = true;
                        break;
                    }
                }
                if (found) continue;
                if (value_lit(other) < 0) {
                    return ci;
                }
                if (!enqueue(other, ci)) {
                    return ci;
                }
                ++propagations;
                ++i;
            }
        }
        return -1;
    }

    void new_decision_level() { trail_lim.push_back((int)trail.size()); }

    void cancel_until(int lvl) {
        if (decision_level() <= lvl) return;
        int target = trail_lim[lvl];
        for (int i = (int)trail.size() - 1; i >= target; --i) {
            int v = std::abs(trail[i]);
            assigns[v] = 0;
            reasons[v] = -1;
            levels[v] = 0;
        }
        trail.resize(target);
        qhead = trail.size();
        trail_lim.resize(lvl);
    }

    void bump_var(int v) {
        var_activity[v] += var_inc;
        if (var_activity[v] > 1e100) {
            for (int i = 1; i <= nvars; ++i) var_activity[i] *= 1e-100;
            var_inc *= 1e-100;
        }
        order_heap.push({var_activity[v], v});
    }

    void decay_activity() { var_inc *= (1.0 / var_decay); }

    void analyze(int confl, std::vector<int> &out_learnt, int &out_btlevel) {
        out_learnt.clear();
        out_learnt.push_back(0);
        int path_c = 0;
        int p = 0;
        int idx = (int)trail.size() - 1;
        ++seen_token;
        if (seen_token == std::numeric_limits<int>::max()) {
            std::fill(seen.begin(), seen.end(), 0);
            seen_token = 1;
        }
        int ci = confl;
        do {
            Clause &c = clauses[ci];
            c.activity += 1.0;
            for (int lit : c.lits) {
                int v = std::abs(lit);
                if (v == std::abs(p)) continue;
                if (seen[v] == seen_token || levels[v] == 0) continue;
                seen[v] = seen_token;
                bump_var(v);
                if (levels[v] == decision_level()) {
                    ++path_c;
                } else {
                    out_learnt.push_back(lit);
                }
            }
            while (idx >= 0 && seen[std::abs(trail[idx])] != seen_token) --idx;
            p = trail[idx--];
            seen[std::abs(p)] = 0;
            --path_c;
            ci = reasons[std::abs(p)];
        } while (path_c > 0);
        out_learnt[0] = -p;

        // Keep only one literal per variable and compute the assertion level.
        out_btlevel = 0;
        int best_i = 1;
        for (int i = 1; i < (int)out_learnt.size(); ++i) {
            int lvl = levels[std::abs(out_learnt[i])];
            if (lvl > out_btlevel) {
                out_btlevel = lvl;
                best_i = i;
            }
        }
        if (out_learnt.size() > 1) std::swap(out_learnt[1], out_learnt[best_i]);
    }

    int pick_branch_lit() {
        while (!order_heap.empty()) {
            int v = order_heap.top().second;
            double a = order_heap.top().first;
            order_heap.pop();
            if (assigns[v] == 0 && std::abs(a - var_activity[v]) <= 1e-9 * (1.0 + std::abs(a))) {
                return phase[v] >= 0 ? v : -v;
            }
        }
        int best = 0;
        double besta = -1.0;
        for (int v = 1; v <= nvars; ++v) {
            if (assigns[v] == 0 && var_activity[v] > besta) {
                besta = var_activity[v];
                best = v;
            }
        }
        if (best == 0) return 0;
        return phase[best] >= 0 ? best : -best;
    }

    bool timed_out() const {
        double elapsed = std::chrono::duration<double>(Clock::now() - start_time).count();
        return elapsed >= time_limit;
    }

    void reduce_db() {
        if ((int)clauses.size() < learnt_limit) return;
        std::vector<int> learnt_ids;
        learnt_ids.reserve(clauses.size());
        for (int i = 0; i < (int)clauses.size(); ++i) {
            if (clauses[i].learnt && clauses[i].lits.size() > 2) learnt_ids.push_back(i);
        }
        if (learnt_ids.size() < 10000) return;
        std::sort(learnt_ids.begin(), learnt_ids.end(), [&](int a, int b) {
            return clauses[a].activity < clauses[b].activity;
        });
        // Lazy deletion would complicate watchers. Instead just raise the limit; memory is ample
        // for the target sizes, and correctness is simpler than database surgery here.
        learnt_limit += 200000;
    }

    enum Result { SAT, UNSAT_UNKNOWN, TIME_UNKNOWN };

    Result solve() {
        start_time = Clock::now();
        if (max_clause_count == 0) max_clause_count = (int)clauses.size() + 300000;
        for (int v = 1; v <= nvars; ++v) {
            if (var_activity[v] > 0.0) order_heap.push({var_activity[v], v});
        }
        int confl = propagate();
        if (confl != -1) return UNSAT_UNKNOWN;

        std::vector<int> learnt;
        int btlevel = 0;
        long long next_restart = restart_limit;
        while (true) {
            if ((conflicts & 1023LL) == 0 && timed_out()) return TIME_UNKNOWN;
            confl = propagate();
            if (confl != -1) {
                ++conflicts;
                if (decision_level() == 0) return UNSAT_UNKNOWN;
                if ((int)clauses.size() >= max_clause_count) return TIME_UNKNOWN;
                analyze(confl, learnt, btlevel);
                cancel_until(btlevel);
                int ci = (int)clauses.size();
                Clause c;
                c.lits = learnt;
                c.learnt = true;
                clauses.push_back(std::move(c));
                if (clauses[ci].lits.size() == 1) {
                    if (!enqueue(clauses[ci].lits[0], ci)) return UNSAT_UNKNOWN;
                } else {
                    attach_clause(ci);
                    if (!enqueue(clauses[ci].lits[0], ci)) return UNSAT_UNKNOWN;
                }
                decay_activity();
                if (conflicts >= next_restart) {
                    cancel_until(0);
                    restart_limit = std::min(100000, (int)(restart_limit * 1.5) + 1);
                    next_restart = conflicts + restart_limit;
                }
                reduce_db();
            } else {
                int next = pick_branch_lit();
                if (next == 0) return SAT;
                new_decision_level();
                enqueue(next, -1);
            }
        }
    }
};

static bool parse_dimacs(const char *path, int &nvars, std::vector<std::vector<int>> &clauses) {
    std::ifstream in(path);
    if (!in) return false;
    std::string tok;
    int declared_clauses = -1;
    while (in >> tok) {
        if (tok == "c") {
            std::string rest;
            std::getline(in, rest);
            continue;
        }
        if (tok == "p") {
            std::string kind;
            in >> kind >> nvars >> declared_clauses;
            break;
        }
    }
    if (nvars <= 0 || declared_clauses < 0) return false;
    clauses.reserve(declared_clauses);
    std::vector<int> cur;
    int lit;
    while (in >> lit) {
        if (lit == 0) {
            clauses.push_back(cur);
            cur.clear();
        } else {
            cur.push_back(lit);
        }
    }
    if (!cur.empty()) return false;
    return (int)clauses.size() == declared_clauses;
}

static bool verify_model(const std::vector<std::vector<int>> &orig, const std::vector<signed char> &assigns) {
    for (size_t ci = 0; ci < orig.size(); ++ci) {
        const auto &c = orig[ci];
        bool ok = false;
        for (int lit : c) {
            int v = std::abs(lit);
            int a = assigns[v];
            if (a == 0) a = -1;
            if ((lit > 0 && a > 0) || (lit < 0 && a < 0)) {
                ok = true;
                break;
            }
        }
        if (!ok) return false;
    }
    return true;
}

struct CliqueHint {
    bool ok = false;
    std::vector<signed char> assign;
};

static int isqrt_exact(int x) {
    int r = (int)std::llround(std::sqrt((double)x));
    return r * r == x ? r : -1;
}

static CliqueHint build_clique_hint(int nvars, const std::vector<std::vector<int>> &clauses) {
    CliqueHint h;
    int unit_count = 0;
    int pstart = nvars + 1;
    for (const auto &c : clauses) {
        if (c.empty()) return h;
        if (c.size() == 1) ++unit_count;
        for (int lit : c) pstart = std::min(pstart, std::abs(lit));
    }
    int n = isqrt_exact(unit_count);
    if (n < 2 || pstart > nvars) return h;
    int C = n * (n - 1) / 2;
    int used = nvars - pstart + 1;
    int k_num = used - 3 * n * C;
    if (k_num <= 0 || k_num % (n * n) != 0) return h;
    int k = k_num / (n * n);
    if (k < 2 || k > n) return h;

    int qstart = pstart + n * C;
    int rstart = qstart + n * C;
    int sstart = rstart + n * n;
    int lstart = sstart + n * C;
    if (lstart + (k - 1) * n * n - 1 != nvars) return h;

    std::vector<std::pair<int, int>> pairs;
    pairs.reserve(C);
    std::vector<std::vector<int>> pair_idx(n, std::vector<int>(n, -1));
    for (int i = 0; i < n; ++i) {
        for (int j = i + 1; j < n; ++j) {
            int idx = (int)pairs.size();
            pairs.push_back({i, j});
            pair_idx[i][j] = pair_idx[j][i] = idx;
        }
    }
    auto P = [&](int t, int i, int j) {
        return pstart + t * C + pair_idx[i][j];
    };
    auto Q = [&](int t, int i, int j) {
        return qstart + t * C + pair_idx[i][j];
    };
    auto R = [&](int t, int v) {
        return rstart + t * n + v;
    };
    auto S = [&](int t, int i, int j) {
        return sstart + t * C + pair_idx[i][j];
    };
    auto L = [&](int t, int v, int a) {
        return lstart + (t * n + v) * (k - 1) + a;
    };

    std::vector<std::vector<unsigned char>> adj(n, std::vector<unsigned char>(n, 0));
    bool saw_edge_block = false;
    for (const auto &c : clauses) {
        if (c.size() != 2) continue;
        int a = c[0], b = c[1];
        if (saw_edge_block && a == pstart && b == -qstart) break;
        if (a > 0 && b < 0 && a >= pstart && a < pstart + (n - 1) * C) {
            int off = a - pstart;
            int t = off / C;
            int idx = off % C;
            int want_q = qstart + (t + 1) * C + idx;
            if (-b == want_q) {
                auto [u, v] = pairs[idx];
                adj[u][v] = adj[v][u] = 1;
                saw_edge_block = true;
            }
        }
    }
    if (!saw_edge_block) return h;

    int full = (n == 31) ? -1 : ((1 << n) - 1);
    std::vector<int> adjmask(n, 0);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) if (adj[i][j]) adjmask[i] |= (1 << j);
    }
    std::vector<int> order;
    order.reserve(n);
    bool strict_model = false;

    auto groups_for_mask = [&](int mask) {
        if (mask == 0 || mask == full) return 1;
        int suffix = full ^ mask;
        std::vector<int> types;
        int x = mask;
        while (x) {
            int lb = x & -x;
            int u = __builtin_ctz((unsigned)lb);
            types.push_back(adjmask[u] & suffix);
            x -= lb;
        }
        std::sort(types.begin(), types.end());
        types.erase(std::unique(types.begin(), types.end()), types.end());
        return (int)types.size() + 1;
    };

    std::vector<int> cur_order;
    cur_order.reserve(n);
    std::vector<int> strict_solution;
    std::unordered_set<int> dead_masks;
    dead_masks.reserve(1000000);
    long long nodes = 0;
    long long node_limit = 5000000;
    if (n == 25 && k == 9) node_limit = 40000000;
    if (n == 25 && k >= 13) node_limit = 80000000;
    auto dead_contains = [&](int mask) {
        return dead_masks.find(mask) != dead_masks.end();
    };
    auto dead_insert = [&](int mask) {
        dead_masks.insert(mask);
    };
    std::function<bool(int)> dfs = [&](int prefix) -> bool {
        if ((int)cur_order.size() == n) {
            strict_solution = cur_order;
            return true;
        }
        if (++nodes > node_limit || dead_contains(prefix)) return false;
        std::vector<std::tuple<int, int, int>> cand;
        for (int v = 0; v < n; ++v) {
            if ((prefix >> v) & 1) continue;
            int next = prefix | (1 << v);
            int next_groups = groups_for_mask(next);
            if (next != full && next_groups > k) continue;
            int suffix = full ^ next;
            int future_deg = __builtin_popcount((unsigned)(adjmask[v] & suffix));
            cand.push_back({next_groups, -future_deg, v});
        }
        std::sort(cand.begin(), cand.end());
        for (auto [groups, neg_deg, v] : cand) {
            cur_order.push_back(v);
            if (dfs(prefix | (1 << v))) return true;
            cur_order.pop_back();
        }
        dead_insert(prefix);
        return false;
    };
    if (dfs(0)) {
        order = strict_solution;
        strict_model = true;
    }

    if (order.empty()) {
        int prefix = 0;
        for (int t = 0; t < n; ++t) {
            int best_v = -1;
            std::tuple<int, int, int> best{1 << 20, 1 << 20, 1 << 20};
            for (int v = 0; v < n; ++v) {
                if ((prefix >> v) & 1) continue;
                int suffix = full ^ (prefix | (1 << v));
                std::vector<int> types;
                int x = prefix;
                while (x) {
                    int lb = x & -x;
                    int u = __builtin_ctz((unsigned)lb);
                    types.push_back(adjmask[u] & suffix);
                    x -= lb;
                }
                std::sort(types.begin(), types.end());
                types.erase(std::unique(types.begin(), types.end()), types.end());
                int groups = (int)types.size() + 1;
                int future_deg = __builtin_popcount((unsigned)(adjmask[v] & suffix));
                std::tuple<int, int, int> score{groups, future_deg, v};
                if (score < best) {
                    best = score;
                    best_v = v;
                }
            }
            order.push_back(best_v);
            prefix |= (1 << best_v);
        }
    }

    {
        int prefix = 0;
        (void)prefix;
    }

    std::vector<int> q_group(n * n, -1);
    h.assign.assign(nvars + 1, -1);
    for (int t = 0; t < n; ++t) {
        std::vector<unsigned char> in_prefix(n, 0), in_old(n, 0);
        for (int i = 0; i <= t; ++i) in_prefix[order[i]] = 1;
        for (int i = 0; i < t; ++i) in_old[order[i]] = 1;

        for (auto [i, j] : pairs) {
            h.assign[P(t, i, j)] = (in_prefix[i] && in_prefix[j]) ? 1 : -1;
        }

        std::vector<int> suffix;
        int suffix_start = strict_model ? t : t + 1;
        for (int i = suffix_start; i < n; ++i) suffix.push_back(order[i]);
        std::vector<std::vector<int>> type_keys;
        std::vector<int> type_gid;
        int next_gid = 0;
        for (int v : order) {
            int gid = -1;
            if (in_old[v]) {
                std::vector<int> key;
                key.reserve(suffix.size());
                for (int w : suffix) key.push_back(adj[v][w] ? 1 : 0);
                for (int i = 0; i < (int)type_keys.size(); ++i) {
                    if (type_keys[i] == key) {
                        gid = type_gid[i];
                        break;
                    }
                }
                if (gid < 0) {
                    gid = next_gid++;
                    type_keys.push_back(std::move(key));
                    type_gid.push_back(gid);
                }
            } else if (v == order[t]) {
                gid = next_gid++;
            } else {
                gid = next_gid++;
            }
            q_group[t * n + v] = gid;
        }
        for (auto [i, j] : pairs) {
            h.assign[Q(t, i, j)] = (q_group[t * n + i] == q_group[t * n + j]) ? 1 : -1;
        }
        for (int v = 0; v < n; ++v) {
            bool rep = true;
            for (int u = 0; u < v; ++u) {
                if (q_group[t * n + u] == q_group[t * n + v]) {
                    rep = false;
                    break;
                }
            }
            h.assign[R(t, v)] = rep ? 1 : -1;
        }
        for (auto [i, j] : pairs) {
            bool sv = h.assign[P(t, i, j)] > 0 && h.assign[R(t, i)] > 0 && h.assign[R(t, j)] > 0;
            h.assign[S(t, i, j)] = sv ? 1 : -1;
        }
        std::vector<int> label(n, 0);
        std::vector<int> reps;
        for (int v = 0; v < n; ++v) {
            if (in_prefix[v] && h.assign[R(t, v)] > 0) reps.push_back(v);
        }
        std::sort(reps.begin(), reps.end());
        int m = (int)reps.size();
        for (int i = 0; i < m; ++i) label[reps[i]] = std::max(0, std::min(k - 1, m - 1 - i));
        for (int v = 0; v < n; ++v) {
            for (int a = 0; a < k - 1; ++a) {
                h.assign[L(t, v, a)] = (label[v] <= a) ? 1 : -1;
            }
        }
    }
    h.ok = true;
    return h;
}

int main(int argc, char **argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    int nvars = 0;
    std::vector<std::vector<int>> orig;
    if (!parse_dimacs(argv[1], nvars, orig)) {
        std::printf("s UNKNOWN\n");
        return 0;
    }

    CliqueHint hint = build_clique_hint(nvars, orig);
    if (hint.ok && verify_model(orig, hint.assign)) {
        std::printf("s SATISFIABLE\n");
        int cnt = 0;
        std::printf("v");
        for (int v = 1; v <= nvars; ++v) {
            int lit = hint.assign[v] > 0 ? v : -v;
            std::printf(" %d", lit);
            if (++cnt == 16) {
                std::printf(" 0\n");
                if (v != nvars) std::printf("v");
                cnt = 0;
            }
        }
        if (cnt != 0) std::printf(" 0\n");
        return 10;
    }

    Solver solver(nvars);
    if (hint.ok) {
        for (int v = 1; v <= nvars && v < (int)hint.assign.size(); ++v) {
            solver.phase[v] = hint.assign[v];
        }
    }
    for (const auto &c : orig) {
        if (!solver.add_clause(c, false)) {
            std::printf("s UNKNOWN\n");
            return 0;
        }
    }

    Solver::Result r = solver.solve();
    if (r == Solver::SAT) {
        for (int v = 1; v <= nvars; ++v) {
            if (solver.assigns[v] == 0) solver.assigns[v] = -1;
        }
        if (!verify_model(orig, solver.assigns)) {
            std::printf("s UNKNOWN\n");
            return 0;
        }
        std::printf("s SATISFIABLE\n");
        const int per_line = 16;
        int cnt = 0;
        std::printf("v");
        for (int v = 1; v <= nvars; ++v) {
            int lit = solver.assigns[v] > 0 ? v : -v;
            std::printf(" %d", lit);
            if (++cnt == per_line) {
                std::printf(" 0\n");
                if (v != nvars) std::printf("v");
                cnt = 0;
            }
        }
        if (cnt != 0) std::printf(" 0\n");
        return 10;
    }
    std::printf("s UNKNOWN\n");
    return 0;
}
