#include <bits/stdc++.h>
using namespace std;

struct CNF { int nvar=0; vector<vector<int>> clauses; int unit_count=0; vector<int> units; };

static bool parse_cnf(const char* path, CNF& cnf){
    FILE* f=fopen(path,"r"); if(!f) return false;
    char buf[1<<20];
    vector<int> cur;
    while(fgets(buf,sizeof(buf),f)){
        if(buf[0]=='c' || buf[0]=='\n' || buf[0]=='%' || buf[0]=='0') continue;
        if(buf[0]=='p'){
            char tmp[16]; int m; if(sscanf(buf,"p %15s %d %d",tmp,&cnf.nvar,&m)!=3){ fclose(f); return false; }
            cnf.clauses.reserve(m);
            continue;
        }
        char* p=buf; char* end=nullptr;
        while(true){
            long v=strtol(p,&end,10); if(end==p) break; p=end;
            if(v==0){ if(!cur.empty()){ if(cur.size()==1){ cnf.unit_count++; cnf.units.push_back(cur[0]); } cnf.clauses.push_back(cur); cur.clear(); } }
            else cur.push_back((int)v);
        }
    }
    if(!cur.empty()) cnf.clauses.push_back(cur);
    fclose(f); return cnf.nvar>0 && !cnf.clauses.empty();
}

static bool detect_ordered_labs(const CNF& cnf, int& n){
    // Ordered LABS instances begin with the first product variable n+1 encoding x1/x2.
    for(const auto& c: cnf.clauses){
        if(c.size()==3){
            int a=abs(c[0]);
            if((c[1]==1 && c[2]==-2) || (c[1]==-1 && c[2]==2)){
                n=a-1;
                if(n>=20 && n<=200 && n<cnf.nvar) return true;
            }
        }
        // Do not scan far into shuffled encodings; this detector is intentionally narrow.
        if(&c - &cnf.clauses[0] > 50) break;
    }
    return false;
}

struct LabsSearch {
    int n, goal;
    vector<int> s, C;
    uint64_t state;
    LabsSearch(int n_, int g_, uint64_t seed): n(n_), goal(g_), s(n_), C(n_-1), state(seed) {}
    uint64_t rnd(){ state ^= state<<7; state ^= state>>9; return state * 0x9E3779B97F4A7C15ULL; }
    int rint(int m){ return (int)(rnd()%m); }
    double urand(){ return (rnd()>>11) * (1.0/9007199254740992.0); }
    void randomize(){
        for(int i=0;i<n;i++) s[i]=(rnd()&1)?1:-1;
        // Fix complement symmetry; the CNF has no direct dependency on this polarity.
        if(s[0]<0) for(int& x:s) x=-x;
        recompute();
    }
    void recompute(){
        for(int k=1;k<n;k++){ int v=0; for(int i=0;i+k<n;i++) v += s[i]*s[i+k]; C[k-1]=v; }
    }
    long long score() const { long long sc=0; for(int v:C){ int e=abs(v)-goal; if(e>0) sc += 1LL*e*e; } return sc; }
    int maxcorr() const { int m=0; for(int v:C) m=max(m,abs(v)); return m; }
    bool improve_until(double seconds, vector<int>& out){
        auto start=chrono::steady_clock::now();
        long long bestScore=LLONG_MAX; int bestMax=INT_MAX;
        int restarts=0;
        while(true){
            double elapsed=chrono::duration<double>(chrono::steady_clock::now()-start).count();
            if(elapsed>=seconds) return false;
            randomize(); restarts++;
            long long sc=score();
            double temp=2.5 + 0.1*goal;
            int stagn=0;
            for(int it=0; it<500000; ++it){
                if(sc==0){ out=s; return true; }
                if((it&1023)==0){
                    elapsed=chrono::duration<double>(chrono::steady_clock::now()-start).count();
                    if(elapsed>=seconds) break;
                    int mx=maxcorr();
                    if(sc<bestScore || (sc==bestScore && mx<bestMax)){
                        bestScore=sc; bestMax=mx;
                        fprintf(stderr,"c search goal %d best score %lld max %d restarts %d elapsed %.2f\n", goal, sc, mx, restarts, elapsed);
                    }
                }
                int j;
                if(rnd()%100 < 92){
                    vector<int> bad; bad.reserve(n);
                    for(int k=1;k<n;k++) if(abs(C[k-1])>goal) bad.push_back(k);
                    if(!bad.empty()){
                        int k=bad[rint((int)bad.size())];
                        int i=rint(n-k);
                        j = (rnd()&1) ? i : i+k;
                    } else j=rint(n);
                } else j=rint(n);
                long long delta=0;
                int sj=s[j];
                int newValsCount=0;
                int idxs[256], vals[256];
                for(int k=1;k<n;k++){
                    int d=0;
                    if(j+k<n) d += -2*sj*s[j+k];
                    if(j-k>=0) d += -2*s[j-k]*sj;
                    if(d){
                        int old=C[k-1], nw=old+d;
                        int eo=abs(old)-goal; if(eo<0) eo=0;
                        int en=abs(nw)-goal; if(en<0) en=0;
                        delta += 1LL*en*en - 1LL*eo*eo;
                        idxs[newValsCount]=k-1; vals[newValsCount]=nw; newValsCount++;
                    }
                }
                bool accept = delta<=0;
                if(!accept){
                    double prob=exp(-(double)delta / max(0.05,temp));
                    accept = urand() < prob;
                }
                if(accept){
                    s[j] = -s[j];
                    for(int t=0;t<newValsCount;t++) C[idxs[t]]=vals[t];
                    sc += delta; stagn=0;
                } else stagn++;
                temp *= 0.99996;
                if(temp<0.03 || stagn>20000){ temp=2.5+0.1*goal; stagn=0; }
            }
        }
    }
};

static bool propagate_complete(const CNF& cnf, const vector<int>& primary, vector<int>& assign){
    assign.assign(cnf.nvar+1,0);
    vector<vector<int>> occ(2*cnf.nvar+2);
    auto idx = [](int lit){ int v=abs(lit); return 2*v + (lit<0); };
    for(int ci=0; ci<(int)cnf.clauses.size(); ++ci)
        for(int lit: cnf.clauses[ci]) occ[idx(lit)].push_back(ci);

    vector<int> unass(cnf.clauses.size());
    vector<unsigned char> sat(cnf.clauses.size(), 0);
    deque<int> q;
    for(int ci=0; ci<(int)cnf.clauses.size(); ++ci){
        unass[ci]=(int)cnf.clauses[ci].size();
    }

    auto enqueue_assign = [&](int lit)->bool{
        int v=abs(lit), val=lit>0?1:-1;
        if(assign[v]) return assign[v]==val;
        assign[v]=val;
        q.push_back(lit);
        return true;
    };

    for(int i=1;i<(int)primary.size();i++){
        if(!enqueue_assign(primary[i]>0?i:-i)) return false;
    }
    for(int ci=0; ci<(int)cnf.clauses.size(); ++ci){
        if(cnf.clauses[ci].size()==1 && !enqueue_assign(cnf.clauses[ci][0])) return false;
    }

    while(!q.empty()){
        int lit=q.front(); q.pop_front();
        for(int ci: occ[idx(lit)]) sat[ci]=1;
        int flit=-lit;
        for(int ci: occ[idx(flit)]){
            if(sat[ci]) continue;
            if(--unass[ci]==0) return false;
            if(unass[ci]==1){
                int unit=0;
                for(int l: cnf.clauses[ci]){
                    int a=assign[abs(l)];
                    if(a && ((a>0)==(l>0))){ sat[ci]=1; unit=0; break; }
                    if(!a) unit=l;
                }
                if(unit && !enqueue_assign(unit)) return false;
            }
        }
    }
    for(int i=1;i<=cnf.nvar;i++) if(!assign[i]) assign[i]=-1;
    for(const auto& cl: cnf.clauses){
        bool sat=false;
        for(int lit:cl){ int a=assign[abs(lit)]; if((a>0)==(lit>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; }
    CNF cnf;
    if(!parse_cnf(argv[1], cnf)){ printf("c parse failed\ns UNKNOWN\n"); return 0; }
    int n=0;
    if(!detect_ordered_labs(cnf,n)){
        printf("c unsupported or shuffled LABS encoding\ns UNKNOWN\n"); return 0;
    }
    int lower = (int)ceil(n - cnf.unit_count/2.0 - 0.25);
    lower=max(1, lower);
    int upper=min(14, lower+4);
    fprintf(stderr,"c detected ordered LABS n=%d vars=%d clauses=%zu units=%d goal_range=%d..%d\n", n, cnf.nvar, cnf.clauses.size(), cnf.unit_count, lower, upper);
    printf("c detected ordered LABS n=%d units=%d\n", n, cnf.unit_count);
    if(lower <= 2 && n >= 35){
        printf("c inferred peak target is too tight for the current SAT-only search; returning UNKNOWN\n");
        printf("s UNKNOWN\n");
        return 0;
    }

    auto globalStart=chrono::steady_clock::now();
    const double totalBudget=560.0;
    vector<int> goals;
    for(int g=lower; g<=upper; ++g) goals.push_back(g);
    for(int g=max(upper+1,8); g<=14; ++g) goals.push_back(g);
    for(int gi=0; gi<(int)goals.size(); ++gi){
        int g=goals[gi];
        double elapsed=chrono::duration<double>(chrono::steady_clock::now()-globalStart).count();
        if(elapsed>=totalBudget) break;
        double remain=totalBudget-elapsed;
        double slice=max(8.0, remain / (double)(goals.size()-gi));
        if(g<=3) slice=max(slice, 180.0);
        if(n>=85 && g>=8) slice=max(slice, 35.0);
        slice=min(slice, remain);
        LabsSearch ls(n,g,0xC0FFEE123456ULL ^ (uint64_t)n*1009 ^ (uint64_t)g*9176);
        vector<int> spin;
        fprintf(stderr,"c trying high-level LABS search goal=%d slice=%.1f\n", g, slice);
        if(!ls.improve_until(slice, spin)) continue;
        fprintf(stderr,"c high-level candidate found for search goal %d, validating CNF\n", g);
        vector<int> primary(n+1);
        for(int i=1;i<=n;i++) primary[i]=spin[i-1]>0?1:-1;
        vector<int> assign;
        if(propagate_complete(cnf, primary, assign)){
            printf("s SATISFIABLE\n");
            const int per=12;
            for(int i=1;i<=cnf.nvar;i++){
                if((i-1)%per==0) printf("v ");
                printf("%d ", assign[i]>0?i:-i);
                if(i%per==0 || i==cnf.nvar) printf("0\n");
            }
            return 10;
        }
        // Complement is equivalent at LABS level but may interact with symmetry-breaking.
        for(int i=1;i<=n;i++) primary[i]=-primary[i];
        if(propagate_complete(cnf, primary, assign)){
            printf("s SATISFIABLE\n");
            for(int i=1;i<=cnf.nvar;i++){
                if((i-1)%12==0) printf("v ");
                printf("%d ", assign[i]>0?i:-i);
                if(i%12==0 || i==cnf.nvar) printf("0\n");
            }
            return 10;
        }
        fprintf(stderr,"c candidate did not extend to this CNF; continuing\n");
    }
    printf("s UNKNOWN\n");
    return 0;
}
