import sys,lzma,random,time,heapq

def read(path):
    op=lzma.open if path.endswith('.xz') else open
    clauses=[]; n=0
    for line in op(path,'rt'):
        if line.startswith('c'): continue
        if line.startswith('p'):
            n=int(line.split()[2]); continue
        lits=list(map(int,line.split()))
        if lits and lits[-1]==0: lits=lits[:-1]
        if lits: clauses.append(lits)
    cover=[c for c in clauses if len(c)>4 and all(x>0 for x in c)]
    primary=max(max(c) for c in cover)
    unit=[c[0] for c in clauses if len(c)==1]
    outs=sorted([abs(u) for u in unit if abs(u)>primary])
    k=sum((1 if v in unit else 0)<<i for i,v in enumerate(outs))
    return primary,k,cover

def solve(primary,k,cover,limit=30):
    M=len(cover)
    occ=[[] for _ in range(primary+1)]
    for i,c in enumerate(cover):
        for v in c: occ[v].append(i)
    degree=[len(occ[v]) for v in range(primary+1)]
    # greedy init
    uncovered=set(range(M)); selected=[]; selected_set=set(); heap=[]
    for v in range(1,primary+1):
        if degree[v]: heapq.heappush(heap,(-degree[v],v))
    while uncovered and len(selected)<k:
        best=None
        while heap:
            neg,v=heapq.heappop(heap); gain=sum(1 for c in occ[v] if c in uncovered)
            if gain==-neg: best=(gain,v); break
            heapq.heappush(heap,(-gain,v))
        if not best or best[0]==0: break
        _,v=best; selected.append(v); selected_set.add(v)
        for ci in occ[v]: uncovered.discard(ci)
    deg_order=sorted(range(1,primary+1), key=lambda v: degree[v], reverse=True)
    for v in deg_order:
        if len(selected)>=k: break
        if v not in selected_set: selected.append(v); selected_set.add(v)
    best_unc=M
    start=time.time()
    tries=0
    while time.time()-start<limit:
        tries+=1
        if tries==1:
            sel=list(selected)
        else:
            # randomized greedy with noise
            sel=[]; ss=set(); unc=set(range(M))
            while unc and len(sel)<k:
                sample=[]
                ci=random.choice(tuple(unc))
                cand=cover[ci]
                if random.random()<0.7:
                    cand=sorted(cand, key=lambda v: sum(1 for c in occ[v] if c in unc), reverse=True)[:min(20,len(cand))]
                v=random.choice(cand)
                if v in ss: continue
                sel.append(v); ss.add(v)
                for c in occ[v]: unc.discard(c)
            for v in deg_order:
                if len(sel)>=k: break
                if v not in ss and (random.random()<0.1 or degree[v]>0): sel.append(v); ss.add(v)
        ss=set(sel)
        cnt=[0]*M
        for v in sel:
            for c in occ[v]: cnt[c]+=1
        unc=[i for i,x in enumerate(cnt) if x==0]
        if len(unc)<best_unc:
            best_unc=len(unc); print('best',best_unc,'try',tries,'time',time.time()-start, file=sys.stderr)
        if not unc: return ss
        no_improve=0
        for step in range(200000):
            if not unc: return ss
            ci=random.choice(unc)
            # choose add from uncovered clause with max gain
            cand=cover[ci]
            if random.random()<0.9:
                add=max(cand, key=lambda v: sum(1 for c in occ[v] if cnt[c]==0))
            else:
                add=random.choice(cand)
            if add in ss: continue
            add_gain=sum(1 for c in occ[add] if cnt[c]==0)
            # choose remove with minimal damage not in current unresolved clause; random among good
            rem_best=[]; minloss=10**9
            protected=set(cand)
            for rem in random.sample(sel, min(len(sel), len(sel))):
                if rem in protected and random.random()<0.95: continue
                loss=sum(1 for c in occ[rem] if cnt[c]==1)
                score=loss
                if score<minloss: minloss=score; rem_best=[rem]
                elif score==minloss: rem_best.append(rem)
            if not rem_best: continue
            rem=random.choice(rem_best)
            # accept if improves or noise
            if add_gain-minloss >=0 or random.random()<0.02:
                ss.remove(rem); ss.add(add); sel[sel.index(rem)]=add
                for c in occ[rem]: cnt[c]-=1
                for c in occ[add]: cnt[c]+=1
                unc=[i for i,x in enumerate(cnt) if x==0]
                if len(unc)<best_unc:
                    best_unc=len(unc); print('best',best_unc,'try',tries,'step',step,'time',time.time()-start, file=sys.stderr)
    return None

for path in sys.argv[1:]:
    p,k,c=read(path); print('SOLVE',path.split('/')[-1],p,k,len(c), file=sys.stderr)
    s=solve(p,k,c,30)
    print(path.split('/')[-1], 'ok', bool(s), 'size', len(s) if s else None)
