import sys,lzma,random,time,heapq,math

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
  xs=list(map(int,line.split()))
  if xs and xs[-1]==0: xs=xs[:-1]
  if xs: clauses.append(xs)
 cover=[c for c in clauses if len(c)>4 and all(x>0 for x in c)]
 p=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)>p)
 k=sum(((v in unit)&1)<<i for i,v in enumerate(outs))
 return p,k,cover

def solve(p,k,cover,T=60):
 M=len(cover); occ=[[] for _ in range(p+1)]
 for i,c in enumerate(cover):
  for v in c: occ[v].append(i)
 w=[1.0]*M; best=10**9; bests=None; start=time.time()
 order=list(range(1,p+1))
 for it in range(100000):
  if time.time()-start>T: break
  uncovered=set(range(M)); sel=[]; ss=set()
  # random restricted candidate list greedy
  while uncovered and len(sel)<k:
   scores=[]
   # collect candidates from a rare uncovered clause sometimes, else all top degree active
   if random.random()<0.35:
    ci=min(uncovered, key=lambda c: len(cover[c]))
    cand=cover[ci]
   else:
    cand=order
   for v in cand:
    if v in ss: continue
    sc=sum(w[c] for c in occ[v] if c in uncovered)
    if sc>0: scores.append((sc,v))
   if not scores: break
   scores.sort(reverse=True)
   rcl=scores[:min(len(scores), 5+it%30)]
   if random.random()<0.80: v=rcl[0][1]
   else: v=random.choice(rcl)[1]
   sel.append(v); ss.add(v)
   for c in occ[v]: uncovered.discard(c)
  # repair/pad
  deg=sorted((sum(w[c] for c in occ[v]),v) for v in range(1,p+1) if v not in ss)
  while len(sel)<k and deg:
   v=deg.pop()[1]; sel.append(v); ss.add(v)
  cnt=[0]*M
  for v in sel:
   for c in occ[v]: cnt[c]+=1
  unc=[i for i in range(M) if cnt[i]==0]
  # local descent swaps
  for st in range(3000):
   if not unc: break
   ci=random.choice(unc)
   add=max(cover[ci], key=lambda v: sum(w[c] for c in occ[v] if cnt[c]==0) if v not in ss else -1)
   if add in ss: continue
   losses=[]
   prot=set(cover[ci])
   for rem in sel:
    if rem in prot: continue
    loss=sum(w[c] for c in occ[rem] if cnt[c]==1)
    losses.append((loss,rem))
   if not losses: continue
   losses.sort()
   rem=random.choice(losses[:min(10,len(losses))])[1]
   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 in range(M) if cnt[i]==0]
  if len(unc)<best:
   best=len(unc); bests=list(sel); print('best',best,'it',it,'t',time.time()-start,file=sys.stderr,flush=True)
   if best==0: return set(sel)
  for c in unc: w[c]+=1.0
  if it%200==0:
   avg=sum(w)/M; w=[x/avg for x in w]
 return None

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