#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <atomic>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

using namespace std;

struct FastInput {
    static constexpr size_t BUFSZ = 1 << 20;
    FILE* f = nullptr;
    char buf[BUFSZ];
    size_t p = 0, n = 0;
    bool bol = true;

    explicit FastInput(const char* path) { f = fopen(path, "rb"); }
    ~FastInput() { if (f) fclose(f); }

    int gc() {
        if (p >= n) {
            n = fread(buf, 1, BUFSZ, f);
            p = 0;
            if (!n) return EOF;
        }
        return buf[p++];
    }

    bool nextInt(int& out) {
        int c, sign = 1, val = 0;
        while (true) {
            c = gc();
            if (c == EOF) return false;
            if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
                if (c == '\n') bol = true;
                continue;
            }
            if (c == 'c' && bol) {
                while ((c = gc()) != EOF && c != '\n') {}
                bol = true;
                continue;
            }
            if (c == '-' || (c >= '0' && c <= '9')) {
                bol = false;
                break;
            }
            bol = false;
        }
        if (c == '-') {
            sign = -1;
            c = gc();
        }
        for (; c >= '0' && c <= '9'; c = gc()) val = val * 10 + (c - '0');
        if (c == '\n') bol = true;
        out = sign * val;
        return true;
    }
};

struct Rng {
    unsigned long long s[4];
    static unsigned long long splitmix64(unsigned long long& x) {
        unsigned long long z = (x += 0x9e3779b97f4a7c15ULL);
        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
        return z ^ (z >> 31);
    }
    explicit Rng(unsigned long long seed) {
        for (int i = 0; i < 4; ++i) s[i] = splitmix64(seed);
    }
    unsigned long long next() {
        const unsigned long long result = s[0] + s[3];
        const unsigned long long t = s[1] << 17;
        s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3];
        s[2] ^= t;
        s[3] = (s[3] << 45) | (s[3] >> 19);
        return result;
    }
    int uniform(int lim) { return (int)(next() % (unsigned)lim); }
    double unit() { return (next() >> 11) * (1.0 / 9007199254740992.0); }
};

struct Solver {
    int vars = 0, clauses = 0, lits_per_clause = 0, min_clause_len = 0, max_clause_len = 0;
    vector<int> lits;
    vector<int> clause_start;
    vector<unsigned char> clause_len;
    vector<vector<int>> occ;
    vector<unsigned char> majority_assign;
    vector<unsigned char> assign;
    vector<unsigned char> satcnt;
    vector<int> unsat, unsat_pos;
    vector<int> candidate_break, candidate_make;
    chrono::steady_clock::time_point deadline;
    struct SearchConfig {
        double alpha = 2.0;
        double beta = 3.0;
        int noise_per_mille = 15;
    };

    int litIndex(int lit) const {
        int v = abs(lit) - 1;
        return (v << 1) | (lit < 0);
    }
    int trueLitIndex(int v) const { return (v << 1) | (assign[v] ? 0 : 1); }
    bool litTrue(int lit) const {
        int v = abs(lit) - 1;
        bool val = assign[v];
        return lit > 0 ? val : !val;
    }
    int clauseBegin(int c) const { return clause_start[c]; }
    int clauseEnd(int c) const { return clause_start[c] + clause_len[c]; }
    bool timedOut() const { return chrono::steady_clock::now() >= deadline; }

    bool parse(const char* path) {
        FastInput in(path);
        if (!in.f) return false;
        int x;
        if (!in.nextInt(x)) return false;
        vars = x;
        if (!in.nextInt(x)) return false;
        clauses = x;
        if (vars <= 0 || clauses <= 0) return false;
        lits.reserve((size_t)clauses * 4);
        clause_start.reserve((size_t)clauses + 1);
        clause_len.reserve(clauses);
        vector<int> occ_count((size_t)vars * 2, 0);
        int lit, cur_len = 0, first_len = -1;
        for (int c = 0; c < clauses; ++c) {
            cur_len = 0;
            clause_start.push_back((int)lits.size());
            while (in.nextInt(lit)) {
                if (lit == 0) break;
                int v = abs(lit);
                if (v < 1 || v > vars) return false;
                lits.push_back(lit);
                occ_count[litIndex(lit)]++;
                cur_len++;
            }
            if (cur_len == 0) return false;
            if (cur_len > 8) return false;
            clause_len.push_back((unsigned char)cur_len);
            if (min_clause_len == 0 || cur_len < min_clause_len) min_clause_len = cur_len;
            max_clause_len = max(max_clause_len, cur_len);
            if (first_len < 0) first_len = cur_len;
            else if (first_len != cur_len) first_len = 0;
        }
        clause_start.push_back((int)lits.size());
        lits_per_clause = first_len;
        if (max_clause_len < 1 || max_clause_len > 8) return false;
        occ.resize((size_t)vars * 2);
        for (size_t i = 0; i < occ.size(); ++i) occ[i].reserve(occ_count[i]);
        for (int c = 0; c < clauses; ++c) {
            for (int p = clauseBegin(c); p < clauseEnd(c); ++p) occ[litIndex(lits[p])].push_back(c);
        }
        majority_assign.assign(vars, 0);
        for (int v = 0; v < vars; ++v) {
            majority_assign[v] = (unsigned char)(occ[v << 1].size() >= occ[(v << 1) | 1].size());
        }
        return true;
    }

    void addUnsat(int c) {
        if (unsat_pos[c] >= 0) return;
        unsat_pos[c] = (int)unsat.size();
        unsat.push_back(c);
    }
    void removeUnsat(int c) {
        int p = unsat_pos[c];
        if (p < 0) return;
        int last = unsat.back();
        unsat[p] = last;
        unsat_pos[last] = p;
        unsat.pop_back();
        unsat_pos[c] = -1;
    }

    void initialize(Rng& rng) {
        assign.assign(vars, 0);
        for (int v = 0; v < vars; ++v) assign[v] = (unsigned char)(rng.next() & 1ULL);
        satcnt.assign(clauses, 0);
        unsat.clear();
        unsat_pos.assign(clauses, -1);
        for (int c = 0; c < clauses; ++c) {
            unsigned char cnt = 0;
            for (int p = clauseBegin(c); p < clauseEnd(c); ++p) cnt += (unsigned char)litTrue(lits[p]);
            satcnt[c] = cnt;
            if (cnt == 0) addUnsat(c);
        }
    }

    void flipVar(int v) {
        int old_true = trueLitIndex(v);
        int new_true = old_true ^ 1;
        for (int c : occ[old_true]) {
            unsigned char nc = --satcnt[c];
            if (nc == 0) addUnsat(c);
        }
        for (int c : occ[new_true]) {
            unsigned char old = satcnt[c]++;
            if (old == 0) removeUnsat(c);
        }
        assign[v] ^= 1;
    }

    int breakCount(int v, int cap = 1000000000) const {
        int br = 0;
        for (int c : occ[trueLitIndex(v)]) {
            if (satcnt[c] == 1 && ++br >= cap) return br;
        }
        return br;
    }

    int makeCount(int v) const {
        int mk = 0;
        int idx = trueLitIndex(v) ^ 1;
        for (int c : occ[idx]) mk += (satcnt[c] == 0);
        return mk;
    }

    bool verify() const {
        for (int c = 0; c < clauses; ++c) {
            bool ok = false;
            for (int p = clauseBegin(c); p < clauseEnd(c); ++p) {
                if (litTrue(lits[p])) { ok = true; break; }
            }
            if (!ok) return false;
        }
        return true;
    }

    bool solve2Sat() {
        if (min_clause_len != 2 || max_clause_len != 2) return false;
        int nodes = vars * 2;
        vector<vector<int>> g(nodes), rg(nodes);
        for (int c = 0; c < clauses; ++c) {
            int base = clauseBegin(c);
            int a = litIndex(lits[base]);
            int b = litIndex(lits[base + 1]);
            int na = a ^ 1, nb = b ^ 1;
            g[na].push_back(b);
            g[nb].push_back(a);
            rg[b].push_back(na);
            rg[a].push_back(nb);
        }
        vector<unsigned char> seen(nodes, 0);
        vector<int> order;
        order.reserve(nodes);
        vector<pair<int, int>> st;
        for (int s = 0; s < nodes; ++s) {
            if (seen[s]) continue;
            seen[s] = 1;
            st.clear();
            st.push_back({s, 0});
            while (!st.empty()) {
                int v = st.back().first;
                int& i = st.back().second;
                if (i < (int)g[v].size()) {
                    int u = g[v][i++];
                    if (!seen[u]) {
                        seen[u] = 1;
                        st.push_back({u, 0});
                    }
                } else {
                    order.push_back(v);
                    st.pop_back();
                }
            }
        }
        vector<int> comp(nodes, -1);
        int cid = 0;
        vector<int> stack;
        stack.reserve(nodes);
        for (int oi = nodes - 1; oi >= 0; --oi) {
            int s = order[oi];
            if (comp[s] != -1) continue;
            comp[s] = cid;
            stack.clear();
            stack.push_back(s);
            while (!stack.empty()) {
                int v = stack.back();
                stack.pop_back();
                for (int u : rg[v]) {
                    if (comp[u] == -1) {
                        comp[u] = cid;
                        stack.push_back(u);
                    }
                }
            }
            cid++;
        }
        assign.assign(vars, 0);
        for (int v = 0; v < vars; ++v) {
            if (comp[v << 1] == comp[(v << 1) | 1]) return false;
            assign[v] = (unsigned char)(comp[v << 1] > comp[(v << 1) | 1]);
        }
        if (verify()) return true;
        for (int v = 0; v < vars; ++v) assign[v] ^= 1;
        return verify();
    }

    struct LocalState {
        const Solver& f;
        vector<unsigned char> assign;
        vector<unsigned char> satcnt;
        vector<int> unsat, unsat_pos, candidate_break, candidate_make;
        vector<double> make_weight, break_weight;
        Rng rng;
        double alpha, beta;
        int noise_per_mille;
        long long restart_limit;
        bool start_majority;

        LocalState(const Solver& formula, unsigned long long seed, double a, double b, int noise, bool majority)
            : f(formula), rng(seed), alpha(a), beta(b), noise_per_mille(noise), start_majority(majority) {
            candidate_break.resize(f.max_clause_len);
            candidate_make.resize(f.max_clause_len);
            restart_limit = max(20000LL, min(5000000LL, 200LL * f.vars));
            int max_occ = 0;
            for (const auto& o : f.occ) max_occ = max(max_occ, (int)o.size());
            make_weight.resize(max_occ + 2);
            break_weight.resize(max_occ + 2);
            for (int i = 0; i <= max_occ + 1; ++i) {
                make_weight[i] = pow((double)i + 1.0, alpha);
                break_weight[i] = 1.0 / pow((double)i + 1.0, beta);
            }
        }

        int trueLitIndex(int v) const { return (v << 1) | (assign[v] ? 0 : 1); }
        bool litTrue(int lit) const {
            int v = abs(lit) - 1;
            bool val = assign[v];
            return lit > 0 ? val : !val;
        }
        void addUnsat(int c) {
            if (unsat_pos[c] >= 0) return;
            unsat_pos[c] = (int)unsat.size();
            unsat.push_back(c);
        }
        void removeUnsat(int c) {
            int p = unsat_pos[c];
            if (p < 0) return;
            int last = unsat.back();
            unsat[p] = last;
            unsat_pos[last] = p;
            unsat.pop_back();
            unsat_pos[c] = -1;
        }
        void initialize(bool use_majority = false) {
            assign.assign(f.vars, 0);
            if (use_majority) {
                assign = f.majority_assign;
            } else {
                for (int v = 0; v < f.vars; ++v) assign[v] = (unsigned char)(rng.next() & 1ULL);
            }
            satcnt.assign(f.clauses, 0);
            unsat.clear();
            unsat_pos.assign(f.clauses, -1);
            for (int c = 0; c < f.clauses; ++c) {
                unsigned char cnt = 0;
                for (int p = f.clauseBegin(c); p < f.clauseEnd(c); ++p) cnt += (unsigned char)litTrue(f.lits[p]);
                satcnt[c] = cnt;
                if (cnt == 0) addUnsat(c);
            }
        }
        void flipVar(int v) {
            int old_true = trueLitIndex(v);
            int new_true = old_true ^ 1;
            for (int c : f.occ[old_true]) {
                unsigned char nc = --satcnt[c];
                if (nc == 0) addUnsat(c);
            }
            for (int c : f.occ[new_true]) {
                unsigned char old = satcnt[c]++;
                if (old == 0) removeUnsat(c);
            }
            assign[v] ^= 1;
        }
        int breakCount(int v) const {
            int br = 0;
            for (int c : f.occ[trueLitIndex(v)]) br += (satcnt[c] == 1);
            return br;
        }
        int makeCount(int v) const {
            int mk = 0;
            int idx = trueLitIndex(v) ^ 1;
            for (int c : f.occ[idx]) mk += (satcnt[c] == 0);
            return mk;
        }
        bool verify() const {
            for (int c = 0; c < f.clauses; ++c) {
                bool ok = false;
                for (int p = f.clauseBegin(c); p < f.clauseEnd(c); ++p) {
                    if (litTrue(f.lits[p])) { ok = true; break; }
                }
                if (!ok) return false;
            }
            return true;
        }
        bool run(const chrono::steady_clock::time_point& deadline,
                 atomic<bool>& found, vector<unsigned char>& final_assign, mutex& final_mu) {
            long long flips_since_restart = 0;
            initialize(start_majority);
            while (!found.load(memory_order_relaxed) && chrono::steady_clock::now() < deadline) {
                if (unsat.empty()) {
                    if (!verify()) return false;
                    lock_guard<mutex> lk(final_mu);
                    if (!found.load(memory_order_relaxed)) {
                        final_assign = assign;
                        found.store(true, memory_order_relaxed);
                    }
                    return true;
                }
                if (++flips_since_restart > restart_limit) {
                    initialize();
                    flips_since_restart = 0;
                    restart_limit = max(20000LL, min(8000000LL, restart_limit + restart_limit / 8));
                    continue;
                }
                int c = unsat[rng.uniform((int)unsat.size())];
                int base = f.clauseBegin(c);
                int len = f.clause_len[c];
                int zeroes[8], zc = 0;
                int best_score = -1000000000, best_var = abs(f.lits[base]) - 1;
                for (int j = 0; j < len; ++j) {
                    int v = abs(f.lits[base + j]) - 1;
                    int br = breakCount(v);
                    int mk = makeCount(v);
                    candidate_break[j] = br;
                    candidate_make[j] = mk;
                    if (br == 0) zeroes[zc++] = v;
                    int score = mk * 8 - br;
                    if (score > best_score) { best_score = score; best_var = v; }
                }
                int vflip;
                if (zc) {
                    vflip = zeroes[rng.uniform(zc)];
                } else if (rng.uniform(1000) < noise_per_mille) {
                    vflip = abs(f.lits[base + rng.uniform(len)]) - 1;
                } else {
                    double sum = 0.0, weights[8];
                    for (int j = 0; j < len; ++j) {
                        weights[j] = make_weight[candidate_make[j]] * break_weight[candidate_break[j]];
                        sum += weights[j];
                    }
                    double r = rng.unit() * sum, acc = 0.0;
                    vflip = best_var;
                    for (int j = 0; j < len; ++j) {
                        acc += weights[j];
                        if (r <= acc) { vflip = abs(f.lits[base + j]) - 1; break; }
                    }
                }
                flipVar(vflip);
            }
            return false;
        }
    };

    vector<SearchConfig> defaultConfigs() const {
        vector<SearchConfig> cfgs(2);
        int effective_k = lits_per_clause ? lits_per_clause : max_clause_len;
        if (effective_k == 3) {
            cfgs[0] = {1.0, 2.10, 20};
            cfgs[1] = {0.9, 2.30, 20};
        } else if (effective_k == 4) {
            cfgs[0] = {1.5, 2.70, 10};
            cfgs[1] = {1.8, 3.00, 0};
        } else if (effective_k == 5) {
            cfgs[0] = {1.8, 3.00, 0};
            cfgs[1] = {2.0, 3.00, 30};
        } else if (effective_k >= 7) {
            cfgs[0] = {2.5, 3.50, 0};
            cfgs[1] = {3.0, 2.50, 40};
        } else {
            cfgs[0] = {2.0, 3.00, 15};
            cfgs[1] = {2.5, 3.50, 0};
        }
        if (const char* e = getenv("SLS_ALPHA")) {
            double a = atof(e);
            for (auto& c : cfgs) c.alpha = a;
        }
        if (const char* e = getenv("SLS_BETA")) {
            double b = atof(e);
            for (auto& c : cfgs) c.beta = b;
        }
        if (const char* e = getenv("SLS_NOISE_PER_MILLE")) {
            int n = atoi(e);
            for (auto& c : cfgs) c.noise_per_mille = n;
        }
        return cfgs;
    }

    bool search(double seconds) {
        deadline = chrono::steady_clock::now() + chrono::milliseconds((int)(seconds * 1000));
        vector<SearchConfig> cfgs = defaultConfigs();
        int threads = 3;
        if (const char* e = getenv("SLS_THREADS")) threads = max(1, min(4, atoi(e)));
        if (vars > 700000) threads = min(threads, 2);
        atomic<bool> found(false);
        mutex final_mu;
        vector<unsigned char> final_assign;
        unsigned long long seed = 0x3141592653589793ULL ^ (unsigned long long)vars * 1000003ULL ^ (unsigned long long)clauses;
        vector<thread> pool;
        for (int t = 0; t < threads; ++t) {
            unsigned long long tseed = seed + 0x9e3779b97f4a7c15ULL * (unsigned long long)(t + 1);
            bool start_majority = (t == 0);
            SearchConfig cfg = cfgs[(size_t)t % cfgs.size()];
            pool.emplace_back([&, tseed, start_majority, cfg]() {
                LocalState st(*this, tseed, cfg.alpha, cfg.beta, cfg.noise_per_mille, start_majority);
                st.run(deadline, found, final_assign, final_mu);
            });
        }
        for (auto& th : pool) th.join();
        if (found.load(memory_order_relaxed)) {
            assign.swap(final_assign);
            return verify();
        }
        return false;
    }

    void printModel() const {
        printf("s SATISFIABLE\n");
        const int per_line = 12;
        for (int i = 0; i < vars; ++i) {
            if (i % per_line == 0) printf("v");
            printf(" %d", assign[i] ? (i + 1) : -(i + 1));
            if (i % per_line == per_line - 1 || i == vars - 1) printf(" 0\n");
        }
    }
};

int main(int argc, char** argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }
    Solver s;
    if (!s.parse(argv[1])) {
        printf("c unsupported or malformed fixed-width CNF\n");
        printf("s UNKNOWN\n");
        return 0;
    }
    if (s.lits_per_clause) {
        fprintf(stderr, "c uniform-random SLS detector: n=%d m=%d k=%d\n", s.vars, s.clauses, s.lits_per_clause);
    } else {
        fprintf(stderr, "c uniform-random SLS detector: n=%d m=%d k=%d..%d mixed\n",
                s.vars, s.clauses, s.min_clause_len, s.max_clause_len);
    }
    if (s.solve2Sat()) {
        s.printModel();
        return 10;
    }
    double budget = 590.0;
    const char* env = getenv("LYMPHOSAT_SOLVER_SECONDS");
    if (env) budget = max(1.0, atof(env));
    if (s.search(budget)) {
        s.printModel();
        return 10;
    }
    printf("s UNKNOWN\n");
    return 0;
}
