#include <algorithm>
#include <chrono>
#include <climits>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <functional>
#include <iostream>
#include <numeric>
#include <queue>
#include <random>
#include <string>
#include <unordered_set>
#include <vector>

using namespace std;

struct Clause {
    vector<int> lits;
    int unassigned = 0;
    int last = 0;
    bool sat = false;
};

static uint64_t edge_key(int a, int b) {
    if (a > b) swap(a, b);
    return (uint64_t)(uint32_t)a << 32 | (uint32_t)b;
}

static bool read_dimacs(const string &path, int &nvar, vector<Clause> &clauses, vector<long long> &size_count) {
    ifstream in(path);
    if (!in) return false;
    string tok;
    int declared_clauses = 0;
    nvar = 0;
    size_count.assign(1024, 0);
    while (in >> tok) {
        if (tok == "c") {
            string rest;
            getline(in, rest);
        } else if (tok == "p") {
            string cnf;
            in >> cnf >> nvar >> declared_clauses;
            clauses.reserve(declared_clauses);
        } else {
            Clause c;
            int lit = stoi(tok);
            while (lit != 0) {
                c.lits.push_back(lit);
                in >> lit;
            }
            if ((int)size_count.size() <= (int)c.lits.size()) size_count.resize(c.lits.size() + 1024, 0);
            size_count[c.lits.size()]++;
            clauses.push_back(std::move(c));
        }
    }
    return nvar > 0 && !clauses.empty();
}

static int infer_n(const vector<long long> &size_count, int nvar) {
    int best = 0;
    for (int k = 2; k < (int)size_count.size(); ++k) {
        if (size_count[k] == k && 1LL * k * k <= nvar) best = k;
    }
    return best;
}

struct Instance {
    int n = 0, w = 0, nvar = 0, prim = 0;
    vector<pair<int,int>> edges;
    vector<vector<int>> adj;
};

static bool extract_instance(const vector<Clause> &clauses, int nvar, int n, Instance &inst) {
    long long prim_ll = 1LL * n * n;
    if (n <= 1 || prim_ll > nvar || prim_ll > INT32_MAX) return false;
    int prim = (int)prim_ll;
    unordered_set<uint64_t> es;
    int min_col = n + 1;
    for (const auto &c : clauses) {
        if (c.lits.size() != 2 || c.lits[0] >= 0 || c.lits[1] >= 0) continue;
        int a = -c.lits[0], b = -c.lits[1];
        if (a > prim || b > prim) continue;
        int ra = (a - 1) / n, ca = (a - 1) % n + 1;
        int rb = (b - 1) / n, cb = (b - 1) % n + 1;
        if (ca == cb && ra != rb) {
            es.insert(edge_key(ra, rb));
            min_col = min(min_col, ca);
        }
    }
    if (es.empty() || min_col > n) return false;
    inst.n = n;
    inst.w = min_col;
    inst.nvar = nvar;
    inst.prim = prim;
    inst.edges.reserve(es.size());
    inst.adj.assign(n, {});
    for (uint64_t k : es) {
        int a = (int)(k >> 32), b = (int)(uint32_t)k;
        inst.edges.push_back({a, b});
        inst.adj[a].push_back(b);
        inst.adj[b].push_back(a);
    }
    sort(inst.edges.begin(), inst.edges.end());
    for (auto &v : inst.adj) sort(v.begin(), v.end());
    return inst.w >= 1 && inst.w <= inst.n;
}

static vector<int> cuthill_order(const Instance &ins, bool rev, bool high_degree_start) {
    int n = ins.n;
    vector<int> starts(n);
    iota(starts.begin(), starts.end(), 0);
    sort(starts.begin(), starts.end(), [&](int a, int b) {
        if (ins.adj[a].size() != ins.adj[b].size())
            return high_degree_start ? ins.adj[a].size() > ins.adj[b].size() : ins.adj[a].size() < ins.adj[b].size();
        return a < b;
    });
    vector<char> seen(n, 0);
    vector<int> order;
    order.reserve(n);
    for (int s : starts) {
        if (seen[s]) continue;
        queue<int> q;
        q.push(s);
        seen[s] = 1;
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            order.push_back(v);
            vector<int> ns;
            for (int u : ins.adj[v]) if (!seen[u]) ns.push_back(u);
            sort(ns.begin(), ns.end(), [&](int a, int b) {
                if (ins.adj[a].size() != ins.adj[b].size()) return ins.adj[a].size() < ins.adj[b].size();
                return a < b;
            });
            for (int u : ns) {
                seen[u] = 1;
                q.push(u);
            }
        }
    }
    if (rev) reverse(order.begin(), order.end());
    return order;
}

static vector<int> labels_from_order(const vector<int> &order, bool flip, int mode) {
    int n = (int)order.size();
    vector<int> pos(n);
    if (mode == 0) {
        int lo = 1, hi = n;
        for (int i = 0; i < n; ++i) {
            bool low = ((i & 1) == 0) ^ flip;
            pos[order[i]] = low ? lo++ : hi--;
        }
    } else if (mode == 1) {
        int lo = 1, hi = n;
        for (int i = 0; i < n; ++i) {
            bool low = ((i / 2) & 1) == 0;
            if (flip) low = !low;
            pos[order[i]] = low ? lo++ : hi--;
        }
    } else {
        for (int i = 0; i < n; ++i) pos[order[i]] = flip ? n - i : i + 1;
    }
    return pos;
}

static pair<int,long long> score_pos(const Instance &ins, const vector<int> &pos, int *mindist = nullptr) {
    int bad = 0, md = ins.n + 1;
    long long cost = 0;
    for (auto [a, b] : ins.edges) {
        int d = abs(pos[a] - pos[b]);
        md = min(md, d);
        if (d < ins.w) {
            bad++;
            long long x = ins.w - d;
            cost += x * x;
        }
    }
    if (mindist) *mindist = md == ins.n + 1 ? 0 : md;
    return {bad, cost};
}

static void normalize_symmetry(vector<int> &pos) {
    int n = (int)pos.size();
    if (!pos.empty() && pos[0] > n / 2) {
        for (int &p : pos) p = n + 1 - p;
    }
}

static vector<int> dfs_window_order(const Instance &ins, double seconds) {
    int n = ins.n, words = (n + 63) / 64;
    vector<vector<uint64_t>> adjm(n, vector<uint64_t>(words, 0));
    for (int v = 0; v < n; ++v)
        for (int u : ins.adj[v]) adjm[v][u >> 6] |= 1ULL << (u & 63);
    vector<int> order;
    vector<char> used(n, 0);
    order.reserve(n);
    auto deadline = chrono::steady_clock::now() + chrono::duration<double>(seconds);
    mt19937_64 rng(0x51A7EULL ^ (uint64_t)n << 20 ^ ins.w);
    long long nodes = 0;

    function<bool()> rec = [&]() -> bool {
        if (++nodes > 50000000) return false;
        if (chrono::steady_clock::now() > deadline) return false;
        int depth = (int)order.size();
        if (depth == n) return true;
        vector<uint64_t> forb(words, 0), rem(words, ~0ULL);
        if (n & 63) rem.back() = (1ULL << (n & 63)) - 1;
        for (int v = 0; v < n; ++v) if (used[v]) rem[v >> 6] &= ~(1ULL << (v & 63));
        int start = max(0, depth - ins.w + 1);
        for (int i = start; i < depth; ++i) {
            int v = order[i];
            for (int w = 0; w < words; ++w) forb[w] |= adjm[v][w];
        }
        vector<int> cand;
        for (int w = 0; w < words; ++w) {
            uint64_t bits = rem[w] & ~forb[w];
            while (bits) {
                int b = __builtin_ctzll(bits);
                int v = (w << 6) + b;
                if (v < n) cand.push_back(v);
                bits &= bits - 1;
            }
        }
        if (cand.empty()) return false;
        shuffle(cand.begin(), cand.end(), rng);
        sort(cand.begin(), cand.end(), [&](int a, int b) {
            auto eval = [&](int v) {
                int recent_conf = 0;
                int st = max(0, depth - ins.w + 2);
                for (int i = st; i < depth; ++i) {
                    int x = order[i];
                    for (int y : ins.adj[v]) if (!used[y] && y != v && y != x) recent_conf++;
                }
                return pair<int,int>(recent_conf, -(int)ins.adj[v].size());
            };
            return eval(a) < eval(b);
        });
        int cap = depth < n / 3 ? min<int>(cand.size(), 28) : (int)cand.size();
        for (int ci = 0; ci < cap; ++ci) {
            int v = cand[ci];
            used[v] = 1;
            order.push_back(v);
            if (rec()) return true;
            order.pop_back();
            used[v] = 0;
        }
        return false;
    };

    vector<int> starts(n);
    iota(starts.begin(), starts.end(), 0);
    sort(starts.begin(), starts.end(), [&](int a, int b) {
        if (ins.adj[a].size() != ins.adj[b].size()) return ins.adj[a].size() > ins.adj[b].size();
        return a < b;
    });
    int start_cap = min(n, 12);
    for (int si = 0; si < start_cap && chrono::steady_clock::now() < deadline; ++si) {
        fill(used.begin(), used.end(), 0);
        order.clear();
        int s = starts[si];
        used[s] = 1;
        order.push_back(s);
        if (rec()) {
            vector<int> pos(n);
            for (int i = 0; i < n; ++i) pos[order[i]] = i + 1;
            normalize_symmetry(pos);
            if (score_pos(ins, pos).first == 0) return pos;
        }
    }
    return {};
}

static void anneal(const Instance &ins, vector<int> &pos, double seconds) {
    int n = ins.n;
    vector<int> at(n + 1);
    for (int v = 0; v < n; ++v) at[pos[v]] = v;
    auto cur = score_pos(ins, pos);
    if (cur.first == 0) return;
    mt19937_64 rng(0xA17B00D5ULL ^ (uint64_t)n << 16 ^ ins.w);
    auto deadline = chrono::steady_clock::now() + chrono::duration<double>(seconds);
    double temp = max(1.0, (double)ins.w * ins.w / 3.0);
    uniform_real_distribution<double> real01(0.0, 1.0);
    vector<pair<int,int>> bad_edges;
    bad_edges.reserve(ins.edges.size());
    for (long long it = 0; chrono::steady_clock::now() < deadline && cur.first > 0; ++it) {
        if ((it & 1023) == 0) {
            bad_edges.clear();
            for (auto e : ins.edges) if (abs(pos[e.first] - pos[e.second]) < ins.w) bad_edges.push_back(e);
            if (bad_edges.empty()) break;
        }
        int v;
        if (!bad_edges.empty() && (rng() % 100) < 80) {
            auto e = bad_edges[rng() % bad_edges.size()];
            v = (rng() & 1) ? e.first : e.second;
        } else {
            v = (int)(rng() % n);
        }
        int qlabel;
        if ((rng() % 100) < 70) {
            int p = pos[v];
            int delta = (int)(rng() % max(2, ins.w * 2 + 1)) - ins.w;
            qlabel = min(n, max(1, p + delta));
        } else {
            qlabel = (int)(rng() % n) + 1;
        }
        int u = at[qlabel];
        if (u == v) continue;
        vector<pair<int,int>> aff;
        aff.reserve(ins.adj[u].size() + ins.adj[v].size());
        for (int x : {u, v}) {
            for (int y : ins.adj[x]) {
                int a = min(x, y), b = max(x, y);
                aff.push_back({a, b});
            }
        }
        sort(aff.begin(), aff.end());
        aff.erase(unique(aff.begin(), aff.end()), aff.end());
        long long oldc = 0, newc = 0;
        int oldb = 0, newb = 0;
        for (auto [a, b] : aff) {
            int d = abs(pos[a] - pos[b]);
            if (d < ins.w) { oldb++; long long x = ins.w - d; oldc += x * x; }
        }
        int pu = pos[u], pv = pos[v];
        swap(pos[u], pos[v]);
        at[pu] = v; at[pv] = u;
        for (auto [a, b] : aff) {
            int d = abs(pos[a] - pos[b]);
            if (d < ins.w) { newb++; long long x = ins.w - d; newc += x * x; }
        }
        long long delta = newc - oldc;
        bool keep = delta <= 0 || real01(rng) < exp(-(double)delta / temp);
        if (keep) {
            cur.first += newb - oldb;
            cur.second += delta;
        } else {
            swap(pos[u], pos[v]);
            at[pu] = u; at[pv] = v;
        }
        temp *= 0.99997;
        if (temp < 0.05) temp = 0.05;
    }
}

static void min_conflict_repair(const Instance &ins, vector<int> &pos, double seconds) {
    int n = ins.n;
    vector<int> at(n + 1);
    for (int v = 0; v < n; ++v) at[pos[v]] = v;
    auto deadline = chrono::steady_clock::now() + chrono::duration<double>(seconds);
    mt19937_64 rng(0xC0FFEE1234ULL ^ (uint64_t)ins.n << 8 ^ ins.w);
    auto cur = score_pos(ins, pos);
    vector<pair<int,int>> bad_edges;
    while (chrono::steady_clock::now() < deadline && cur.first > 0) {
        bad_edges.clear();
        for (auto e : ins.edges) if (abs(pos[e.first] - pos[e.second]) < ins.w) bad_edges.push_back(e);
        if (bad_edges.empty()) return;
        shuffle(bad_edges.begin(), bad_edges.end(), rng);
        bool improved = false;
        int probes = min<int>(bad_edges.size(), 80);
        long long best_delta = LLONG_MAX;
        int best_u = -1, best_v = -1;
        int best_bad_delta = 0;
        for (int bi = 0; bi < probes; ++bi) {
            auto [a0, b0] = bad_edges[bi];
            for (int endpoint_try = 0; endpoint_try < 2; ++endpoint_try) {
                int v = endpoint_try ? b0 : a0;
                vector<int> labels;
                labels.reserve(n);
                for (int u : ins.adj[v]) {
                    int pu = pos[u];
                    if (pu - ins.w >= 1) labels.push_back(pu - ins.w);
                    if (pu + ins.w <= n) labels.push_back(pu + ins.w);
                    if (pu - ins.w + 1 >= 1) labels.push_back(pu - ins.w + 1);
                    if (pu + ins.w - 1 <= n) labels.push_back(pu + ins.w - 1);
                }
                for (int t = 0; t < 24; ++t) labels.push_back((int)(rng() % n) + 1);
                sort(labels.begin(), labels.end());
                labels.erase(unique(labels.begin(), labels.end()), labels.end());
                for (int lab : labels) {
                    int u = at[lab];
                    if (u == v) continue;
                    vector<pair<int,int>> aff;
                    for (int x : {u, v}) {
                        for (int y : ins.adj[x]) aff.push_back({min(x, y), max(x, y)});
                    }
                    sort(aff.begin(), aff.end());
                    aff.erase(unique(aff.begin(), aff.end()), aff.end());
                    long long oldc = 0, newc = 0;
                    int oldb = 0, newb = 0;
                    for (auto [x, y] : aff) {
                        int d = abs(pos[x] - pos[y]);
                        if (d < ins.w) { oldb++; long long z = ins.w - d; oldc += z * z; }
                    }
                    swap(pos[u], pos[v]);
                    for (auto [x, y] : aff) {
                        int d = abs(pos[x] - pos[y]);
                        if (d < ins.w) { newb++; long long z = ins.w - d; newc += z * z; }
                    }
                    swap(pos[u], pos[v]);
                    long long delta = newc - oldc;
                    int bdelta = newb - oldb;
                    if (bdelta < best_bad_delta || (bdelta == best_bad_delta && delta < best_delta)) {
                        best_bad_delta = bdelta;
                        best_delta = delta;
                        best_u = u;
                        best_v = v;
                    }
                }
            }
        }
        if (best_u >= 0 && (best_bad_delta < 0 || best_delta < 0 || (rng() % 100) < 6)) {
            int pu = pos[best_u], pv = pos[best_v];
            swap(pos[best_u], pos[best_v]);
            at[pu] = best_v;
            at[pv] = best_u;
            cur = score_pos(ins, pos);
            improved = true;
        }
        if (!improved) {
            anneal(ins, pos, min(1.0, max(0.05, chrono::duration<double>(deadline - chrono::steady_clock::now()).count())));
            cur = score_pos(ins, pos);
        }
    }
}

static vector<int> find_labeling(const Instance &ins) {
    vector<int> best;
    pair<int,long long> bests = {INT32_MAX, LLONG_MAX};
    for (bool high : {false, true}) {
        for (bool rev : {false, true}) {
            auto order = cuthill_order(ins, rev, high);
            for (int mode = 0; mode < 3; ++mode) {
                for (bool flip : {false, true}) {
                    auto pos = labels_from_order(order, flip, mode);
                    normalize_symmetry(pos);
                    auto sc = score_pos(ins, pos);
                    if (sc < bests) {
                        bests = sc;
                        best = std::move(pos);
                    }
                }
            }
        }
    }
    if (bests.first == 0) return best;
    if (ins.n <= 140) {
        auto exactish = dfs_window_order(ins, 70.0);
        if (!exactish.empty()) return exactish;
    }
    double budget = ins.n <= 130 ? 60.0 : (ins.n <= 300 ? 30.0 : 45.0);
    min_conflict_repair(ins, best, budget * 0.70);
    if (score_pos(ins, best).first != 0) anneal(ins, best, budget * 0.30);
    if (score_pos(ins, best).first != 0) min_conflict_repair(ins, best, budget * 0.20);
    normalize_symmetry(best);
    return best;
}

static bool complete_and_check(const vector<Clause> &clauses_in, const Instance &ins, const vector<int> &pos, vector<int8_t> &assign) {
    if (score_pos(ins, pos).first != 0) return false;
    int nvar = ins.nvar, prim = ins.prim, n = ins.n;
    assign.assign(nvar + 1, 0);
    for (int v = 1; v <= prim; ++v) assign[v] = -1;
    for (int r = 0; r < n; ++r) assign[r * n + pos[r]] = 1;

    vector<Clause> clauses = clauses_in;
    int auxn = nvar - prim;
    vector<vector<int>> occ_pos(auxn + 1), occ_neg(auxn + 1);
    queue<int> q;
    for (int i = 0; i < (int)clauses.size(); ++i) {
        auto &c = clauses[i];
        c.sat = false;
        c.unassigned = 0;
        c.last = 0;
        for (int lit : c.lits) {
            int v = abs(lit);
            int8_t val = assign[v];
            if (val && ((lit > 0 && val > 0) || (lit < 0 && val < 0))) {
                c.sat = true;
                break;
            }
            if (val == 0) {
                c.unassigned++;
                c.last = lit;
                int av = v - prim;
                if (av <= 0) return false;
                (lit > 0 ? occ_pos[av] : occ_neg[av]).push_back(i);
            }
        }
        if (!c.sat) {
            if (c.unassigned == 0) return false;
            if (c.unassigned == 1) q.push(c.last);
        }
    }
    while (!q.empty()) {
        int lit = q.front();
        q.pop();
        int v = abs(lit);
        int8_t val = lit > 0 ? 1 : -1;
        if (assign[v] == val) continue;
        if (assign[v] == -val) return false;
        assign[v] = val;
        int av = v - prim;
        auto &sat_occ = val > 0 ? occ_pos[av] : occ_neg[av];
        for (int ci : sat_occ) clauses[ci].sat = true;
        auto &unsat_occ = val > 0 ? occ_neg[av] : occ_pos[av];
        for (int ci : unsat_occ) {
            auto &c = clauses[ci];
            if (c.sat) continue;
            c.unassigned--;
            if (c.unassigned == 0) return false;
            if (c.unassigned == 1) {
                int last = 0;
                for (int l2 : c.lits) {
                    int8_t vv = assign[abs(l2)];
                    if (vv == 0) { last = l2; break; }
                    if ((l2 > 0 && vv > 0) || (l2 < 0 && vv < 0)) {
                        c.sat = true;
                        break;
                    }
                }
                if (!c.sat) {
                    if (last == 0) return false;
                    q.push(last);
                }
            }
        }
    }
    for (int v = prim + 1; v <= nvar; ++v) if (assign[v] == 0) assign[v] = -1;
    for (const auto &c : clauses_in) {
        bool sat = false;
        for (int lit : c.lits) {
            int8_t val = assign[abs(lit)];
            if ((lit > 0 && val > 0) || (lit < 0 && val < 0)) {
                sat = true;
                break;
            }
        }
        if (!sat) return false;
    }
    return true;
}

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    int nvar = 0;
    vector<Clause> clauses;
    vector<long long> size_count;
    if (!read_dimacs(argv[1], nvar, clauses, size_count)) {
        cout << "c parse failed\ns UNKNOWN\n";
        return 0;
    }
    int n = infer_n(size_count, nvar);
    Instance ins;
    if (!extract_instance(clauses, nvar, n, ins)) {
        cout << "c unsupported structure\ns UNKNOWN\n";
        return 0;
    }
    cerr << "c detected n=" << ins.n << " w=" << ins.w << " m=" << ins.edges.size() << "\n";
    auto pos = find_labeling(ins);
    int md = 0;
    auto sc = score_pos(ins, pos, &md);
    if (sc.first != 0) {
        cout << "c no antibandwidth labeling found n=" << ins.n << " w=" << ins.w << " bad=" << sc.first << " mindist=" << md << "\n";
        cout << "s UNKNOWN\n";
        return 0;
    }
    vector<int8_t> assign;
    if (!complete_and_check(clauses, ins, pos, assign)) {
        cout << "c high-level labeling did not complete to a checked CNF model\ns UNKNOWN\n";
        return 0;
    }
    cout << "c antibandwidth model n=" << ins.n << " w=" << ins.w << " m=" << ins.edges.size() << " mindist=" << md << "\n";
    cout << "s SATISFIABLE\n";
    const int per_line = 20;
    for (int i = 1; i <= nvar; ++i) {
        if ((i - 1) % per_line == 0) cout << "v ";
        cout << (assign[i] > 0 ? i : -i) << ' ';
        if (i % per_line == 0) cout << "0\n";
    }
    if (nvar % per_line != 0) cout << "0\n";
    return 10;
}
