// Planning SAT Solver v8 — from-scratch CDCL
// Proof deletion with correct IDs, FLP with time cap, optimized propagation

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <cstdint>
#include <climits>
#include <sys/time.h>
#include <unistd.h>

static double g_start;
static double g_tlimit = 575.0;
static inline double now(){struct timeval t;gettimeofday(&t,0);return t.tv_sec+t.tv_usec*1e-6;}
static inline bool timeout(){return now()-g_start>g_tlimit;}

static inline int  V(int l)  {return l>>1;}
static inline int  P(int v)  {return v<<1;}
static inline int  N(int v)  {return (v<<1)|1;}
static inline int  FL(int l) {return l^1;}
static inline bool IP(int l) {return !(l&1);}
static inline int  D2L(int d){return d>0?P(d):N(-d);}

enum:uint8_t{UU=0,FF=1,TT=2};
static const uint32_t UNDEF32=UINT32_MAX;

struct Clause{
    uint32_t hdr;
    uint32_t extra; // lbd for learned, 0 for original
    int lits[0];
    int  sz() const{return(int)(hdr>>2);}
    bool ln() const{return hdr&1;}
    bool dl() const{return hdr&2;}
    void sd(){hdr|=2;}
};

struct CA{
    std::vector<uint32_t> m;
    CA(){m.reserve(1<<20);}
    uint32_t al(const int*ls,int n,bool lr,uint32_t lb=0){
        uint32_t o=(uint32_t)m.size();
        m.resize(m.size()+2+n);
        Clause*c=(Clause*)&m[o];
        c->hdr=((uint32_t)n<<2)|(uint32_t)lr;
        c->extra=lb;
        for(int i=0;i<n;i++)c->lits[i]=ls[i];
        return o;
    }
    Clause*p(uint32_t r){return(Clause*)&m[r];}
};

struct W{uint32_t cr;int bk;};

struct Solver{
    int nv;
    CA ca;
    std::vector<std::vector<W>> ws;
    std::vector<std::vector<int>> bins;
    std::vector<uint8_t> val;
    std::vector<int> lv;
    std::vector<uint32_t> rsn;
    std::vector<double> act;
    std::vector<uint8_t> ph;
    std::vector<bool> sn;
    std::vector<int> trail,tlim;
    int qh;
    std::vector<int> hp;std::vector<int> hps;
    double vi;
    std::vector<uint32_t> orig,lrn;
    uint64_t nc,nd,np,nr;
    double ef,es;uint64_t csr;
    uint64_t nxr;int ri;
    uint32_t bin_conf; // pre-allocated binary conflict clause
    
    FILE*pf;bool dp;
    std::vector<char> pbuf;
    static const int PBUF_LIMIT = 1<<24;
    uint64_t proof_bytes;
    static const uint64_t PROOF_MAX = 4000000000ULL;
    bool proof_too_large;
    
    int proof_next_id;
    std::vector<int> lrn_proof_id;
    
    bool ok;
    int n_binary_orig, n_binary_learned;
    int n_orig_total;
    int n_clauses_parsed;
    
    static const uint32_t BIN_REASON_BIT = 0x80000000u;
    static inline bool is_bin_reason(uint32_t r){return r!=UNDEF32&&(r&BIN_REASON_BIT);}
    static inline int bin_other(uint32_t r){return(int)(r&0x7FFFFFFFu);}
    static inline uint32_t mk_bin(int o){return BIN_REASON_BIT|(uint32_t)o;}

    void pf_flush(){
        if(!dp||!pf||pbuf.empty())return;
        fwrite(pbuf.data(),1,pbuf.size(),pf);
        proof_bytes+=pbuf.size();
        pbuf.clear();
        if(proof_bytes>PROOF_MAX)proof_too_large=true;
    }
    void pf_w(const char*s,int len){
        if(!dp||proof_too_large)return;
        if((int)pbuf.size()+len>PBUF_LIMIT)pf_flush();
        pbuf.insert(pbuf.end(),s,s+len);
    }

    // Heap
    void hu(int i){int x=hp[i];while(i>0){int p2=(i-1)>>1;if(act[hp[p2]]>=act[x])break;hp[i]=hp[p2];hps[hp[p2]]=i;i=p2;}hp[i]=x;hps[x]=i;}
    void hd(int i){int x=hp[i],n2=(int)hp.size();while(1){int c=2*i+1;if(c>=n2)break;if(c+1<n2&&act[hp[c+1]]>act[hp[c]])c++;if(act[x]>=act[hp[c]])break;hp[i]=hp[c];hps[hp[c]]=i;i=c;}hp[i]=x;hps[x]=i;}
    void hi(int v){if(hps[v]>=0)return;hps[v]=(int)hp.size();hp.push_back(v);hu((int)hp.size()-1);}
    int hpop(){int v=hp[0];hps[v]=-1;if(hp.size()>1){hp[0]=hp.back();hps[hp[0]]=0;hp.pop_back();hd(0);}else hp.pop_back();return v;}
    void vb(int v){act[v]+=vi;if(act[v]>1e100){for(int i=1;i<=nv;i++)act[i]*=1e-100;vi*=1e-100;}if(hps[v]>=0)hu(hps[v]);}

    void init(int n){
        nv=n;int nl=2*(n+1);
        ws.resize(nl);bins.resize(nl);val.assign(nl,UU);
        lv.assign(n+1,-1);rsn.assign(n+1,UNDEF32);
        act.assign(n+1,0.0);ph.assign(n+1,0);
        sn.assign(n+1,false);
        hps.assign(n+1,-1);
        for(int v=1;v<=n;v++)hi(v);
        vi=1.0;qh=0;
        nc=nd=np=nr=0;ef=es=0;csr=0;
        nxr=4000;ri=500;
        pf=nullptr;dp=false;ok=true;
        proof_bytes=0;proof_too_large=false;
        proof_next_id=0;
        n_binary_orig=0;n_binary_learned=0;
        n_orig_total=0;n_clauses_parsed=0;
        bin_conf=0; // unused
    }

    int dll(){return(int)tlim.size();}
    
    void enq(int l,uint32_t r){
        val[l]=TT;val[FL(l)]=FF;
        lv[V(l)]=dll();rsn[V(l)]=r;
        trail.push_back(l);
    }

    bool addO(std::vector<int>&ls){
        n_clauses_parsed++;
        if(!ok)return false;
        std::sort(ls.begin(),ls.end());
        int j=0;
        for(int i=0;i<(int)ls.size();i++){
            if(val[ls[i]]==TT)return true;
            if(val[ls[i]]==FF)continue;
            if(i>0&&ls[i]==ls[i-1])continue;
            if(i>0&&ls[i]==(ls[i-1]^1))return true;
            ls[j++]=ls[i];
        }
        ls.resize(j);
        if(ls.empty()){ok=false;return false;}
        if(ls.size()==1){enq(ls[0],UNDEF32);ok=(prop()==UNDEF32);return ok;}
        if(ls.size()==2){
            bins[FL(ls[0])].push_back(ls[1]);
            bins[FL(ls[1])].push_back(ls[0]);
            n_binary_orig++;n_orig_total++;
            return true;
        }
        uint32_t cr=ca.al(ls.data(),ls.size(),false);
        orig.push_back(cr);
        ws[FL(ls[0])].push_back({cr,ls[1]});
        ws[FL(ls[1])].push_back({cr,ls[0]});
        n_orig_total++;
        return true;
    }

    // Initialize variable activities based on occurrence counts
    void initAct(){
        for(int v=1;v<=nv;v++){
            double a=(double)(bins[P(v)].size()+bins[N(v)].size());
            // Add long clause participation
            a += ws[P(v)].size() + ws[N(v)].size();
            act[v]=a;
        }
        // Rebuild heap
        hp.clear();hps.assign(nv+1,-1);
        for(int v=1;v<=nv;v++)if(val[P(v)]==UU){hps[v]=(int)hp.size();hp.push_back(v);}
        // Heapify bottom-up
        for(int i=((int)hp.size()-2)/2;i>=0;i--)hd(i);
    }

    uint32_t prop(){
        while(qh<(int)trail.size()){
            int p2=trail[qh++];np++;
            // Binary propagation
            const auto&b=bins[p2];
            for(int k=0,bsz=(int)b.size();k<bsz;k++){
                int o=b[k];
                if(val[o]==TT)continue;
                if(val[o]==FF){
                    static int tb[2]; tb[0]=FL(p2);tb[1]=o;
                    return ca.al(tb,2,false);
                }
                enq(o,mk_bin(FL(p2)));
            }
            // Long clause propagation
            auto&w=ws[p2];int ff=FL(p2);
            int i=0,j=0,sz=(int)w.size();
            while(i<sz){
                if(val[w[i].bk]==TT){w[j++]=w[i++];continue;}
                uint32_t cr=w[i].cr;
                Clause*c=ca.p(cr);
                if(c->dl()){i++;continue;}
                int csz=c->sz();int*cl=c->lits;
                if(cl[0]==ff){cl[0]=cl[1];cl[1]=ff;}
                int f=cl[0];
                if(val[f]==TT){w[j]=w[i];w[j].bk=f;j++;i++;continue;}
                bool found=false;
                for(int k=2;k<csz;k++){
                    if(val[cl[k]]!=FF){
                        cl[1]=cl[k];cl[k]=ff;
                        ws[FL(cl[1])].push_back({cr,f});
                        found=true;i++;break;
                    }
                }
                if(found)continue;
                w[j++]=w[i++];
                if(val[f]==FF){while(i<sz)w[j++]=w[i++];w.resize(j);return cr;}
                enq(f,cr);
            }
            w.resize(j);
        }
        return UNDEF32;
    }

    void bt(int level){
        while((int)trail.size()>tlim[level]){
            int l=trail.back();trail.pop_back();
            int v=V(l);
            val[P(v)]=UU;val[N(v)]=UU;
            lv[v]=-1;rsn[v]=UNDEF32;
            ph[v]=IP(l)?1:0;
            hi(v);
        }
        tlim.resize(level);qh=(int)trail.size();
    }

    std::vector<int> lb,tc,sk;

    void analyze(uint32_t co,std::vector<int>&out,int&btl){
        out.clear();out.push_back(0);tc.clear();
        Clause*c=ca.p(co);int pc=0,idx=(int)trail.size()-1,pp=-1;
        auto processLit=[&](int q){
            int v2=V(q);if(sn[v2]||lv[v2]==0)return;
            sn[v2]=true;tc.push_back(v2);vb(v2);
            if(lv[v2]>=dll())pc++;else out.push_back(q);
        };
        for(int k=0;k<c->sz();k++)processLit(c->lits[k]);
        while(true){
            while(!sn[V(trail[idx])])idx--;
            pp=trail[idx--];sn[V(pp)]=false;pc--;
            if(pc<=0)break;
            uint32_t r=rsn[V(pp)];
            if(is_bin_reason(r)){processLit(bin_other(r));}
            else{Clause*rc=ca.p(r);for(int k=1;k<rc->sz();k++)processLit(rc->lits[k]);}
        }
        out[0]=FL(pp);
        if(out.size()==1)btl=0;
        else{int mx=1;for(int i=2;i<(int)out.size();i++)if(lv[V(out[i])]>lv[V(out[mx])])mx=i;
            std::swap(out[1],out[mx]);btl=lv[V(out[1])];}
        uint32_t ab=0;for(int i=1;i<(int)out.size();i++)ab|=1u<<(lv[V(out[i])]&31);
        int j2=1;for(int i=1;i<(int)out.size();i++){
            if(rsn[V(out[i])]==UNDEF32||!litR(out[i],ab))out[j2++]=out[i];}
        out.resize(j2);
        for(int v2:tc)sn[v2]=false;
    }

    bool litR(int l,uint32_t ab){
        sk.clear();sk.push_back(l);int top=(int)tc.size();
        while(!sk.empty()){
            int q=sk.back();sk.pop_back();uint32_t r=rsn[V(q)];
            if(r==UNDEF32){for(int k=top;k<(int)tc.size();k++)sn[tc[k]]=false;tc.resize(top);return false;}
            if(is_bin_reason(r)){
                int rv=V(bin_other(r));
                if(!sn[rv]&&lv[rv]!=0){
                    if(rsn[rv]!=UNDEF32&&(ab&(1u<<(lv[rv]&31)))){sn[rv]=true;sk.push_back(bin_other(r));tc.push_back(rv);}
                    else{for(int k=top;k<(int)tc.size();k++)sn[tc[k]]=false;tc.resize(top);return false;}
                }
            }else{
                Clause*c=ca.p(r);
                for(int i=1;i<c->sz();i++){int rv=V(c->lits[i]);
                    if(sn[rv]||lv[rv]==0)continue;
                    if(rsn[rv]!=UNDEF32&&(ab&(1u<<(lv[rv]&31)))){sn[rv]=true;sk.push_back(c->lits[i]);tc.push_back(rv);}
                    else{for(int k=top;k<(int)tc.size();k++)sn[tc[k]]=false;tc.resize(top);return false;}
                }
            }
        }
        return true;
    }

    uint32_t compLBD(std::vector<int>&cl){
        static std::vector<uint64_t>stamp;static uint64_t cnt=0;
        if(stamp.size()<=(size_t)(nv+1))stamp.resize(nv+2,0);
        cnt++;uint32_t lbd=0;
        for(int l:cl){int vv=lv[V(l)];if(stamp[vv]!=cnt){stamp[vv]=cnt;lbd++;}}
        return lbd;
    }

    // Proof logging
    char fb[256];
    void plog(const int*ls,int n){
        if(!dp||proof_too_large)return;
        int pos=sprintf(fb,"rup ");pf_w(fb,pos);
        for(int i=0;i<n;i++){int v2=V(ls[i]);pos=sprintf(fb,"1 %sx%d ",IP(ls[i])?"":"~",v2);pf_w(fb,pos);}
        pf_w(">= 1 ;\n",7);
        proof_next_id++;
    }
    void pempty(){if(!dp||proof_too_large)return;pf_w("rup >= 1 ;\n",11);proof_next_id++;}
    
    void pdel(int id){
        if(!dp||proof_too_large)return;
        int pos=sprintf(fb,"del id %d ;\n",id);
        pf_w(fb,pos);
    }

    void addL(std::vector<int>&cl,uint32_t lbd){
        plog(cl.data(),cl.size());
        int pid = proof_next_id - 1;
        
        if(cl.size()==1){enq(cl[0],UNDEF32);return;}
        if(cl.size()==2){
            bins[FL(cl[0])].push_back(cl[1]);
            bins[FL(cl[1])].push_back(cl[0]);
            n_binary_learned++;
            enq(cl[0],mk_bin(cl[1]));
            return;
        }
        uint32_t cr=ca.al(cl.data(),cl.size(),true,lbd);
        lrn.push_back(cr);
        lrn_proof_id.push_back(pid);
        ws[FL(cl[0])].push_back({cr,cl[1]});
        ws[FL(cl[1])].push_back({cr,cl[0]});
        enq(cl[0],cr);
    }

    bool locked(uint32_t cr){
        Clause*c=ca.p(cr);return val[c->lits[0]]==TT&&rsn[V(c->lits[0])]==cr;
    }

    void reduceDB(){
        std::vector<int> idx(lrn.size());
        for(int i=0;i<(int)idx.size();i++)idx[i]=i;
        std::sort(idx.begin(),idx.end(),[&](int a,int b){
            return ca.p(lrn[a])->extra < ca.p(lrn[b])->extra;
        });
        
        int keep=(int)lrn.size()/2;
        std::vector<uint32_t> new_lrn;
        std::vector<int> new_pid;
        
        for(int ii=0;ii<(int)idx.size();ii++){
            int i=idx[ii];
            Clause*c=ca.p(lrn[i]);
            if(c->dl())continue;
            if(ii>=keep&&c->extra>2&&c->sz()>2&&!locked(lrn[i])){
                c->sd();
                pdel(lrn_proof_id[i]);
            }else{
                new_lrn.push_back(lrn[i]);
                new_pid.push_back(lrn_proof_id[i]);
            }
        }
        lrn=std::move(new_lrn);
        lrn_proof_id=std::move(new_pid);
    }

    // ==================== Failed Literal Probing ====================
    bool flp(){
        if(dll()!=0)return true;
        int fixed=0, probes=0;
        int max_probes=std::min(nv*2, 2000000);
        double flp_limit=now()-g_start+std::min(10.0, g_tlimit*0.02);
        bool changed=true;

        while(changed&&now()-g_start<flp_limit){
            changed=false;
            for(int v=1;v<=nv&&probes<max_probes&&now()-g_start<flp_limit;v++){
                if(val[P(v)]!=UU)continue;
                probes++;
                
                int saved=trail.size();
                tlim.push_back(saved);
                enq(P(v),UNDEF32);
                bool pos_fail=(prop()!=UNDEF32);
                bt(dll()-1);
                
                if(pos_fail){
                    int neg=N(v);
                    plog(&neg,1);
                    enq(neg,UNDEF32);
                    if(prop()!=UNDEF32)return false;
                    fixed++;changed=true;
                    continue;
                }
                
                saved=trail.size();
                tlim.push_back(saved);
                enq(N(v),UNDEF32);
                bool neg_fail=(prop()!=UNDEF32);
                bt(dll()-1);
                
                if(neg_fail){
                    int pos=P(v);
                    plog(&pos,1);
                    enq(pos,UNDEF32);
                    if(prop()!=UNDEF32)return false;
                    fixed++;changed=true;
                }
            }
        }
        fprintf(stderr,"c FLP: fixed=%d probes=%d\n",fixed,probes);
        return true;
    }

    // Luby sequence for restarts
    static int luby_seq(int i){
        int k=1;
        while(k<i+1) k=2*k+1;
        while(k-1!=i){k=(k-1)>>1;i=i%k;}
        // Return power of 2
        int v=1;
        int t=k;
        while(t>1){t=(t-1)>>1;v*=2;}
        return v;
    }

    int solve(){
        if(!ok){pempty();return 20;}
        
        if(!flp()){pempty();return 20;}

        while(1){
            uint32_t co=prop();
            if(co!=UNDEF32){
                nc++;csr++;
                if(dll()==0){pempty();return 20;}
                int btl;analyze(co,lb,btl);
                uint32_t lbd=compLBD(lb);
                ef=0.03*lbd+0.97*ef;
                es=0.00003*lbd+0.99997*es;
                bt(btl);
                addL(lb,lbd);
                vi*=(1.0/0.95);
                if(nc>=nxr){reduceDB();nxr+=ri;ri+=100;}
            }else{
                // Glucose-style restart
                if(nc>100&&csr>50&&es>0&&ef/es>1.25){bt(0);csr=0;nr++;}
                
                if((nd&0x3FFF)==0&&timeout())return 0;
                int v=-1;while(!hp.empty()){v=hpop();if(val[P(v)]==UU)break;v=-1;}
                if(v==-1)return 10;
                nd++;tlim.push_back((int)trail.size());
                enq(ph[v]?P(v):N(v),UNDEF32);
            }
        }
    }

    bool verify(const char*fn){
        FILE*f=fopen(fn,"r");if(!f)return false;
        std::vector<char>buf(1<<20);int cn=0;bool cs=false,ic=false;
        while(fgets(buf.data(),(int)buf.size(),f)){
            if(buf[0]=='c'||buf[0]=='p')continue;const char*pp=buf.data();
            while(1){while(*pp==' '||*pp=='\t'||*pp=='\n'||*pp=='\r')pp++;
                if(!*pp)break;char*e;long d=strtol(pp,&e,10);if(e==pp)break;pp=e;
                if(d==0){if(ic){cn++;if(!cs){fclose(f);return false;}}cs=false;ic=false;continue;}
                ic=true;if(val[D2L((int)d)]==TT)cs=true;}}
        fclose(f);fprintf(stderr,"c VERIFY: %d clauses OK\n",cn);return true;
    }

    void printModel(){
        printf("s SATISFIABLE\nv ");int c=0;
        for(int v=1;v<=nv;v++){printf("%d ",val[P(v)]==TT?v:-v);if(++c%20==0)printf("\nv ");}
        printf("0\n");
    }
};

static inline int readI(const char*&p){
    while(*p==' '||*p=='\t'||*p=='\n'||*p=='\r')p++;
    int neg=0;if(*p=='-'){neg=1;p++;}
    int r=0;while(*p>='0'&&*p<='9'){r=r*10+(*p-'0');p++;}
    return neg?-r:r;
}

bool parse(const char*fn,Solver&S){
    FILE*f=fopen(fn,"r");if(!f)return false;
    fseek(f,0,SEEK_END);long fsz=ftell(f);fseek(f,0,SEEK_SET);
    if(fsz>2000000000L){
        const int BS=1<<20;char*buf=(char*)malloc(BS);
        int nv2=0,ncl2=0;bool hdr=false;std::vector<int>cl;
        while(fgets(buf,BS,f)){
            if(buf[0]=='c')continue;
            if(!hdr&&buf[0]=='p'){sscanf(buf,"p cnf %d %d",&nv2,&ncl2);S.init(nv2);hdr=true;
                fprintf(stderr,"c %d vars %d cls (stream)\n",nv2,ncl2);continue;}
            if(!hdr)continue;const char*p2=buf;
            while(1){while(*p2==' '||*p2=='\t'||*p2=='\n'||*p2=='\r')p2++;
                if(!*p2)break;int d=readI(p2);
                if(d==0){S.addO(cl);cl.clear();}else cl.push_back(D2L(d));}
        }
        free(buf);fclose(f);return true;
    }
    char*data=(char*)malloc(fsz+1);if(!data){fclose(f);return false;}
    size_t rd=fread(data,1,fsz,f);data[rd]=0;fclose(f);
    const char*p2=data;int nv2=0,ncl2=0;
    while(*p2){
        if(*p2=='c'){while(*p2&&*p2!='\n')p2++;if(*p2)p2++;continue;}
        if(*p2=='p'){p2++;while(*p2==' ')p2++;while(*p2&&*p2!=' ')p2++;nv2=readI(p2);ncl2=readI(p2);while(*p2&&*p2!='\n')p2++;if(*p2)p2++;break;}
        while(*p2&&*p2!='\n')p2++;if(*p2)p2++;
    }
    S.init(nv2);fprintf(stderr,"c %d vars %d cls\n",nv2,ncl2);
    std::vector<int>cl;
    while(*p2){while(*p2==' '||*p2=='\t'||*p2=='\n'||*p2=='\r')p2++;
        if(!*p2)break;if(*p2=='c'){while(*p2&&*p2!='\n')p2++;if(*p2)p2++;continue;}
        int d=readI(p2);if(d==0){S.addO(cl);cl.clear();}else cl.push_back(D2L(d));}
    free(data);return true;
}

int main(int argc,char**argv){
    if(argc!=3){fprintf(stderr,"usage: solver <cnf> <pbp>\n");return 1;}
    g_start=now();
    Solver S;fprintf(stderr,"c Solver v8\n");
    if(!parse(argv[1],S)){printf("s UNKNOWN\n");return 0;}
    fprintf(stderr,"c Parse: %.2fs binary=%d\n",now()-g_start,S.n_binary_orig);
    
    S.pf=fopen(argv[2],"w");
    if(S.pf){S.dp=true;fprintf(S.pf,"pseudo-Boolean proof version 2.0\n");}
    S.proof_next_id=S.n_clauses_parsed+1;
    
    int r=S.solve();S.pf_flush();
    fprintf(stderr,"c C=%llu D=%llu P=%llu R=%llu L=%d binL=%d\n",
        (unsigned long long)S.nc,(unsigned long long)S.nd,(unsigned long long)S.np,(unsigned long long)S.nr,
        (int)S.lrn.size(),S.n_binary_learned);
    fprintf(stderr,"c ProofBytes=%llu Time=%.2fs\n",(unsigned long long)S.proof_bytes,now()-g_start);
    
    if(r==10){
        if(S.verify(argv[1])){S.printModel();if(S.pf)fclose(S.pf);return 10;}
        printf("s UNKNOWN\n");if(S.pf)fclose(S.pf);return 0;
    }
    if(r==20){
        if(S.dp&&S.pf&&!S.proof_too_large){
            S.pempty();S.pf_flush();
            fprintf(S.pf,"output NONE\nconclusion UNSAT : -1\nend pseudo-Boolean proof\n");
            fclose(S.pf);S.pf=nullptr;
            printf("s UNSATISFIABLE\n");return 20;
        }
        if(S.pf)fclose(S.pf);printf("s UNKNOWN\n");return 0;
    }
    printf("s UNKNOWN\n");if(S.pf)fclose(S.pf);return 0;
}
