from time import*
from fractions import*
from collections import*
from itertools import*
def solve1a():
dotprod = lambda A,B: sum(a*b for a,b in zip(A,B))
for n in xrange(1,7):
numer=0
for A in product([1,-1],repeat=n):
for B in product([1,0,0,-1],repeat=n):
if not dotprod(A,B):
if not dotprod(A[1:]+A[:1],B):
numer+=1
denom=8**n
print n,Fraction(numer,denom)
solve1a()
print '----'
def solve1b():
for n in xrange(1,8):
def f(i,a,b,s,t):
if i==n:
return not s and not t+a*b
res=0
for A in 1,-1:
for B in 1,0,0,-1:
res+=f(i+1,a,B,s+A*B,t+A*b)
return res
numer=0
for a in 1,-1:
for b in 1,0,0,-1:
numer+=f(1,a,b,a*b,0)
denom=8**n
print n,Fraction(numer,denom)
solve1b()
print '----'
def solve2a():
dotprod = lambda A,B: sum(a*b for a,b in zip(A,B))
for n in xrange(2,7):
numer=0
for A in product([1,-1],repeat=n):
for B in product([1,0,0,-1],repeat=n):
if not dotprod(A,B):
if not dotprod(A[1:]+A[:1],B):
if not dotprod(A[2:]+A[:2],B):
numer+=1
denom=8**n
print n,Fraction(numer,denom)
solve2a()
print '----'
def solve2b():
for n in xrange(2,8):
def f(i,a1,a2,b1,b2,s,t,u):
if i==n:
return not s and not t+a1*b2 and not u+a1*b1+a2*b2
res=0
for A in 1,-1:
for B in 1,0,0,-1:
res+=f(i+1,a1,a2,b2,B,s+A*B,t+A*b2,u+A*b1)
return res
numer=0
for a1 in 1,-1:
for b1 in 1,0,0,-1:
for a2 in 1,-1:
for b2 in 1,0,0,-1:
numer+=f(2,a1,a2,b1,b2,a1*b1+a2*b2,a2*b1,0)
denom=8**n
print n,Fraction(numer,denom)
solve2b()
print '----'
def solve2c():
X=defaultdict(lambda:0)
numer=0
for a1 in 1,-1:
for b1 in 1,0,0,-1:
for a2 in 1,-1:
for b2 in 1,0,0,-1:
if not a1*b1+a2*b2 and not a2*b1+a1*b2:
numer+=1
X[(a1,a2,b1,b2,a1*b1+a2*b2,a2*b1,0)]+=1
denom=8**2
print 2,Fraction(numer,denom)
for n in xrange(3,17):
Y=defaultdict(lambda:0)
numer=0
for a1,a2,b1,b2,s,t,u in X:
c=X[(a1,a2,b1,b2,s,t,u)]
for A in 1,-1:
for B in 1,0,0,-1:
if not s+A*B and not t+A*b2+a1*B and not u+A*b1+a1*b2+a2*B:
numer+=c
Y[(a1,a2,b2,B,s+A*B,t+A*b2,u+A*b1)]+=c
denom=8**n
print n,Fraction(numer,denom)
X=Y
solve2c()
print '----'
def solve2d():
N_MAX=28
T=time()
n=2
Y=defaultdict(lambda:0)
numer=0
for a1 in [1]:
for b1 in (1,0):
for a2 in (1,-1):
for b2 in (1,0,0,-1):
if not a1*b1+a2*b2 and not a2*b1+a1*b2:
numer+=1
Y[(a1,a2,b1,b2,a1*b1+a2*b2,a2*b1,0)]+=1
thresh=N_MAX-1
while time() <= T+10:
print('%d %s'%(n,Fraction(numer,8**n/4)))
n+=1
X=Y
Y=defaultdict(lambda:0)
numer=0
if thresh<2:
print('reached MAX_N with %.2f seconds remaining'%(T+10-time()))
return
for a1,a2,b1,b2,s,t,u in X:
if not ( abs(s)<thresh and abs(t)<thresh+1 and abs(u)<thresh+2 ):
continue
c=X[(a1,a2,b1,b2,s,t,u)]
# 1,1
if not s+1 and not t+b2+a1 and not u+b1+a1*b2+a2: numer+=c
Y[(a1,a2,b2,1,s+1,t+b2,u+b1)]+=c
# -1,1
if not s-1 and not t-b2+a1 and not u-b1+a1*b2+a2: numer+=c
Y[(a1,a2,b2,1,s-1,t-b2,u-b1)]+=c
# 1,-1
if not s-1 and not t+b2-a1 and not u+b1+a1*b2-a2: numer+=c
Y[(a1,a2,b2,-1,s-1,t+b2,u+b1)]+=c
# -1,-1
if not s+1 and not t-b2-a1 and not u-b1+a1*b2-a2: numer+=c
Y[(a1,a2,b2,-1,s+1,t-b2,u-b1)]+=c
# 1,0
c+=c
if not s and not t+b2 and not u+b1+a1*b2: numer+=c
Y[(a1,a2,b2,0,s,t+b2,u+b1)]+=c
# -1,0
if not s and not t-b2 and not u-b1+a1*b2: numer+=c
Y[(a1,a2,b2,0,s,t-b2,u-b1)]+=c
thresh-=1
solve2d()
ZnJvbSB0aW1lIGltcG9ydCoKZnJvbSBmcmFjdGlvbnMgaW1wb3J0Kgpmcm9tIGNvbGxlY3Rpb25zIGltcG9ydCoKZnJvbSBpdGVydG9vbHMgaW1wb3J0KgoKZGVmIHNvbHZlMWEoKToKCWRvdHByb2QgPSBsYW1iZGEgQSxCOiBzdW0oYSpiIGZvciBhLGIgaW4gemlwKEEsQikpCgkKCWZvciBuIGluIHhyYW5nZSgxLDcpOgoJCW51bWVyPTAKCQlmb3IgQSBpbiBwcm9kdWN0KFsxLC0xXSxyZXBlYXQ9bik6CgkJCWZvciBCIGluIHByb2R1Y3QoWzEsMCwwLC0xXSxyZXBlYXQ9bik6CgkJCQlpZiBub3QgZG90cHJvZChBLEIpOgoJCQkJCWlmIG5vdCBkb3Rwcm9kKEFbMTpdK0FbOjFdLEIpOgoJCQkJCQludW1lcis9MQoJCWRlbm9tPTgqKm4KCQlwcmludCBuLEZyYWN0aW9uKG51bWVyLGRlbm9tKQoKc29sdmUxYSgpCnByaW50ICctLS0tJwoKZGVmIHNvbHZlMWIoKToKCWZvciBuIGluIHhyYW5nZSgxLDgpOgoJCWRlZiBmKGksYSxiLHMsdCk6CgkJCWlmIGk9PW46CgkJCQlyZXR1cm4gbm90IHMgYW5kIG5vdCB0K2EqYgoJCQkKCQkJcmVzPTAKCQkJCgkJCWZvciBBIGluIDEsLTE6CgkJCQlmb3IgQiBpbiAxLDAsMCwtMToKCQkJCQlyZXMrPWYoaSsxLGEsQixzK0EqQix0K0EqYikKCQkJCgkJCXJldHVybiByZXMKCQkKCQludW1lcj0wCgkJCgkJZm9yIGEgaW4gMSwtMToKCQkJZm9yIGIgaW4gMSwwLDAsLTE6CgkJCQludW1lcis9ZigxLGEsYixhKmIsMCkKCQkKCQlkZW5vbT04KipuCgkJCgkJcHJpbnQgbixGcmFjdGlvbihudW1lcixkZW5vbSkKCnNvbHZlMWIoKQpwcmludCAnLS0tLScKCmRlZiBzb2x2ZTJhKCk6Cglkb3Rwcm9kID0gbGFtYmRhIEEsQjogc3VtKGEqYiBmb3IgYSxiIGluIHppcChBLEIpKQoJCglmb3IgbiBpbiB4cmFuZ2UoMiw3KToKCQludW1lcj0wCgkJZm9yIEEgaW4gcHJvZHVjdChbMSwtMV0scmVwZWF0PW4pOgoJCQlmb3IgQiBpbiBwcm9kdWN0KFsxLDAsMCwtMV0scmVwZWF0PW4pOgoJCQkJaWYgbm90IGRvdHByb2QoQSxCKToKCQkJCQlpZiBub3QgZG90cHJvZChBWzE6XStBWzoxXSxCKToKCQkJCQkJaWYgbm90IGRvdHByb2QoQVsyOl0rQVs6Ml0sQik6CgkJCQkJCQludW1lcis9MQoJCWRlbm9tPTgqKm4KCQlwcmludCBuLEZyYWN0aW9uKG51bWVyLGRlbm9tKQoKc29sdmUyYSgpCnByaW50ICctLS0tJwoKZGVmIHNvbHZlMmIoKToKCWZvciBuIGluIHhyYW5nZSgyLDgpOgoJCWRlZiBmKGksYTEsYTIsYjEsYjIscyx0LHUpOgoJCQlpZiBpPT1uOgoJCQkJcmV0dXJuIG5vdCBzIGFuZCBub3QgdCthMSpiMiBhbmQgbm90IHUrYTEqYjErYTIqYjIKCQkJCgkJCXJlcz0wCgkJCQoJCQlmb3IgQSBpbiAxLC0xOgoJCQkJZm9yIEIgaW4gMSwwLDAsLTE6CgkJCQkJcmVzKz1mKGkrMSxhMSxhMixiMixCLHMrQSpCLHQrQSpiMix1K0EqYjEpCgkJCQoJCQlyZXR1cm4gcmVzCgkJCgkJbnVtZXI9MAoJCQoJCWZvciBhMSBpbiAxLC0xOgoJCQlmb3IgYjEgaW4gMSwwLDAsLTE6CgkJCQlmb3IgYTIgaW4gMSwtMToKCQkJCQlmb3IgYjIgaW4gMSwwLDAsLTE6CgkJCQkJCW51bWVyKz1mKDIsYTEsYTIsYjEsYjIsYTEqYjErYTIqYjIsYTIqYjEsMCkKCQkKCQlkZW5vbT04KipuCgkJCgkJcHJpbnQgbixGcmFjdGlvbihudW1lcixkZW5vbSkKCnNvbHZlMmIoKQpwcmludCAnLS0tLScKCmRlZiBzb2x2ZTJjKCk6CglYPWRlZmF1bHRkaWN0KGxhbWJkYTowKQoJCgludW1lcj0wCgkKCWZvciBhMSBpbiAxLC0xOgoJCWZvciBiMSBpbiAxLDAsMCwtMToKCQkJZm9yIGEyIGluIDEsLTE6CgkJCQlmb3IgYjIgaW4gMSwwLDAsLTE6CgkJCQkJaWYgbm90IGExKmIxK2EyKmIyIGFuZCBub3QgYTIqYjErYTEqYjI6CgkJCQkJCW51bWVyKz0xCgkJCQkJWFsoYTEsYTIsYjEsYjIsYTEqYjErYTIqYjIsYTIqYjEsMCldKz0xCgkKCWRlbm9tPTgqKjIKCXByaW50IDIsRnJhY3Rpb24obnVtZXIsZGVub20pCgkKCWZvciBuIGluIHhyYW5nZSgzLDE3KToKCQlZPWRlZmF1bHRkaWN0KGxhbWJkYTowKQoJCW51bWVyPTAKCQlmb3IgYTEsYTIsYjEsYjIscyx0LHUgaW4gWDoKCQkJYz1YWyhhMSxhMixiMSxiMixzLHQsdSldCgkJCWZvciBBIGluIDEsLTE6CgkJCQlmb3IgQiBpbiAxLDAsMCwtMToKCQkJCQlpZiBub3QgcytBKkIgYW5kIG5vdCB0K0EqYjIrYTEqQiBhbmQgbm90IHUrQSpiMSthMSpiMithMipCOgoJCQkJCQludW1lcis9YwoJCQkJCVlbKGExLGEyLGIyLEIscytBKkIsdCtBKmIyLHUrQSpiMSldKz1jCgkJZGVub209OCoqbgoJCXByaW50IG4sRnJhY3Rpb24obnVtZXIsZGVub20pCgkJWD1ZCgpzb2x2ZTJjKCkKcHJpbnQgJy0tLS0nCgpkZWYgc29sdmUyZCgpOgoJTl9NQVg9MjgKCQoJVD10aW1lKCkKCQoJbj0yCglZPWRlZmF1bHRkaWN0KGxhbWJkYTowKQoJbnVtZXI9MAoJCglmb3IgYTEgaW4gWzFdOgoJCWZvciBiMSBpbiAoMSwwKToKCQkJZm9yIGEyIGluICgxLC0xKToKCQkJCWZvciBiMiBpbiAoMSwwLDAsLTEpOgoJCQkJCWlmIG5vdCBhMSpiMSthMipiMiBhbmQgbm90IGEyKmIxK2ExKmIyOgoJCQkJCQludW1lcis9MQoJCQkJCVlbKGExLGEyLGIxLGIyLGExKmIxK2EyKmIyLGEyKmIxLDApXSs9MQoJCgl0aHJlc2g9Tl9NQVgtMQoJCgl3aGlsZSB0aW1lKCkgPD0gVCsxMDoKCQlwcmludCgnJWQgJXMnJShuLEZyYWN0aW9uKG51bWVyLDgqKm4vNCkpKQoJCQoJCW4rPTEKCQlYPVkKCQlZPWRlZmF1bHRkaWN0KGxhbWJkYTowKQoJCW51bWVyPTAKCQkKCQlpZiB0aHJlc2g8MjoKCQkJcHJpbnQoJ3JlYWNoZWQgTUFYX04gd2l0aCAlLjJmIHNlY29uZHMgcmVtYWluaW5nJyUoVCsxMC10aW1lKCkpKQoJCQlyZXR1cm4KCQkKCQlmb3IgYTEsYTIsYjEsYjIscyx0LHUgaW4gWDoKCQkJaWYgbm90ICggYWJzKHMpPHRocmVzaCBhbmQgYWJzKHQpPHRocmVzaCsxIGFuZCBhYnModSk8dGhyZXNoKzIgKToKCQkJCWNvbnRpbnVlCgkJCQoJCQljPVhbKGExLGEyLGIxLGIyLHMsdCx1KV0KCQkJCgkJCSMgMSwxCgkJCQoJCQlpZiBub3QgcysxIGFuZCBub3QgdCtiMithMSBhbmQgbm90IHUrYjErYTEqYjIrYTI6IG51bWVyKz1jCgkJCVlbKGExLGEyLGIyLDEscysxLHQrYjIsdStiMSldKz1jCgkJCQoJCQkjIC0xLDEKCQkJCgkJCWlmIG5vdCBzLTEgYW5kIG5vdCB0LWIyK2ExIGFuZCBub3QgdS1iMSthMSpiMithMjogbnVtZXIrPWMKCQkJWVsoYTEsYTIsYjIsMSxzLTEsdC1iMix1LWIxKV0rPWMKCQkJCgkJCSMgMSwtMQoJCQkKCQkJaWYgbm90IHMtMSBhbmQgbm90IHQrYjItYTEgYW5kIG5vdCB1K2IxK2ExKmIyLWEyOiBudW1lcis9YwoJCQlZWyhhMSxhMixiMiwtMSxzLTEsdCtiMix1K2IxKV0rPWMKCQkJCgkJCSMgLTEsLTEKCQkJCgkJCWlmIG5vdCBzKzEgYW5kIG5vdCB0LWIyLWExIGFuZCBub3QgdS1iMSthMSpiMi1hMjogbnVtZXIrPWMKCQkJWVsoYTEsYTIsYjIsLTEscysxLHQtYjIsdS1iMSldKz1jCgkJCQoJCQkjIDEsMAoJCQkKCQkJYys9YwoJCQkKCQkJaWYgbm90IHMgYW5kIG5vdCB0K2IyIGFuZCBub3QgdStiMSthMSpiMjogbnVtZXIrPWMKCQkJWVsoYTEsYTIsYjIsMCxzLHQrYjIsdStiMSldKz1jCgkJCQoJCQkjIC0xLDAKCQkJCgkJCWlmIG5vdCBzIGFuZCBub3QgdC1iMiBhbmQgbm90IHUtYjErYTEqYjI6IG51bWVyKz1jCgkJCVlbKGExLGEyLGIyLDAscyx0LWIyLHUtYjEpXSs9YwoJCQoJCXRocmVzaC09MQoKc29sdmUyZCgp