- # Mystery Square
- import codejam as gcj
- def bn(n):
- return bin(n)[2:] # Python annoyingly prepends '0b'
- def int_sqrt(n): # Find int(n**0.5) - works for very large numbers
- x, y = n, (n + 1) // 2
- while y < x:
- x, y = y, (y + n // y) // 2
- return x
- def replace_gaps(X, gaps, digits): # (?00??1?, 1011) -> (1)00(0)(1)1(1)
- digits = bn(digits).zfill(len(gaps))
- for i, j in enumerate(gaps):
- X[j] = digits[i]
- def find_square(S):
- if len(S) > 1:
- top, bottom = S[:len(S) // 2], S[len(S) // 2:]
- return try_find_odd(top[:], bottom[:]) or 4 * find_square(top + bottom[:-2])
- return 1
- def try_find_odd(top, bottom):
- if bottom[-1] == '1' or bottom[-1] == '?':
- bottom[-1] = '1'
- if bottom.count('?') >= top.count('?'):
- gaps = [i for i, c in enumerate(top) if c == '?']
- for digits in range(2**len(gaps)):
- replace_gaps(top, gaps, digits)
- r = int_sqrt(int(''.join(top) + '1' * len(bottom), 2))
- if all(a in (b, '?') for a, b in zip(top + bottom, bn(r**2))):
- return r**2
- else:
- gaps = [i for i, c in enumerate(bottom) if c == '?']
- for digits in range(2**len(gaps)):
- replace_gaps(bottom, gaps, digits)
- b = int(''.join(bottom), 2)
- for second_digit in 0, 1:
- r = 2 * second_digit + 1
- for k in range(3, len(bottom) + 1):
- if r**2 % 2**(k + 1) != b % 2**(k + 1):
- r += 2**(k - 1)
- r |= 2**(k - 1)
- if all(a in (b, '?') for a, b in zip(top + bottom, bn(r**2))):
- return r**2
- T = gcj.read_input('i')
- for _case in range(1, T + 1):
- S = gcj.read_input('s{}')
- print('Case #%d:' % _case, bn(find_square(S)))