├── 2004
└── bio2004q3.py
├── 2006
├── bio2006q1.py
└── bio2006q3.py
├── 2007
└── bio2007q3.py
├── 2008
└── bio2008.py
├── 2009
├── bio2009q1.py
├── bio2009q2.py
└── bio2009q3.py
├── 2010
├── bio10q1.py
└── bio10q2.py
├── 2011
├── bio2011q1.py
├── bio2011q2.py
└── bio2011q3.py
├── 2012
├── bio2012q1.py
└── bio2012q3.py
├── 2013
└── bio2013q3.py
├── 2014
├── bio14q1.py
├── bio14q2.py
└── bio2014q3.py
├── 2015
├── bio15q1.py
├── bio15q2.py
└── bio2015q3.py
├── 2016
├── bio16q1.py
├── bio16q2.py
└── bio16q3v2.py
├── 2017
├── bio17q1.py
├── bio17q2.py
└── bio17q3v2.py
├── 2018
├── bio2018q1.py
├── bio2018q2.py
└── bio2018q3ownImproved.py
├── 2019
├── bio19q1.py
├── bio19q2.py
└── bio19q3.py
├── 2020
├── bio20q1.py
├── bio20q2.py
└── bio20q3.py
├── 2021
├── BIO2021q1.py
├── BIO2021q2.py
└── BIO2021q3.py
├── .idea
├── .gitignore
├── British Informatics Olympiad.iml
├── inspectionProfiles
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── README.md
└── docs
├── googled40a215ed9e79ad6.html
└── index.html
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/British Informatics Olympiad.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/2004/bio2004q3.py:
--------------------------------------------------------------------------------
1 | morse_code = {"a": ".-", "h": "....", "o": "---", "v": "...-", "b": "-...", "i": "..", "p": ".--.",
2 | "w": ".--", "c": "-.-.", "j": ".---", "q": "--.-", "x": "-..-", "d": "-..", "k": "-.-",
3 | "r": ".-.", "y": "-.--", "e": ".", "l": ".-..", "s": "...", "z": "--..", "f": "..-.",
4 | "m": "--", "t": "-", "g": "--.", "n": "-.", "u": "..-"}
5 | ans = 0
6 |
7 |
8 | def find_words(morse, extra_letters, original_length):
9 | global ans
10 | if original_length == 0:
11 | return
12 | for letter in morse_code:
13 | c = len(morse_code[letter])
14 | if c > extra_letters:
15 | continue
16 | if morse_code[letter] == morse[:c]:
17 | if c == extra_letters:
18 | if original_length == 1:
19 | ans += 1
20 | else:
21 | find_words(morse[c:], extra_letters-c, original_length-1)
22 |
23 |
24 | NAME = ""
25 | SCHOOL = ""
26 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
27 | word = input()
28 | m = "".join(morse_code[letter] for letter in word)
29 | find_words(m, len(m), len(word))
30 |
31 | print(ans)
32 |
--------------------------------------------------------------------------------
/2006/bio2006q1.py:
--------------------------------------------------------------------------------
1 | from string import ascii_uppercase
2 |
3 | def occurences(word):
4 | return tuple(word.count(letter) for letter in ascii_uppercase)
5 |
6 | NAME = ""
7 | SCHOOL = ""
8 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
9 | w1 = input()
10 | w2 = input()
11 |
12 | if occurences(w1) == occurences(w2):
13 | print("Anagrams")
14 | else:
15 | print("Not anagrams")
--------------------------------------------------------------------------------
/2006/bio2006q3.py:
--------------------------------------------------------------------------------
1 | from functools import lru_cache
2 | NAME = ""
3 | SCHOOL = ""
4 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
5 | s, d = (int(x) for x in input().split())
6 |
7 | @lru_cache(maxsize=None)
8 | def make_num(target, throws_left, throws_so_far=0, points=0):
9 | if points == target:
10 | if throws_left == 0:
11 | return 1
12 | elif points > target:
13 | return 0
14 | elif throws_left == 0:
15 | return 0
16 |
17 | total = 0
18 | if throws_so_far == 0:
19 | for i in range(1,21):
20 | total += make_num(target, throws_left - 1, throws_so_far + 1, points + i*2)
21 | else:
22 | for i in range(1,21):
23 | total += make_num(target, throws_left - 1, throws_so_far + 1, points + i)
24 | return total
25 |
26 | print(make_num(s, d))
--------------------------------------------------------------------------------
/2007/bio2007q3.py:
--------------------------------------------------------------------------------
1 | string = input()
2 | s, p = (int(x) for x in input().split())
3 |
4 | def count(letter, steps):
5 | if letter == "A":
6 | a, b = 1, 0
7 | for i in range(steps):
8 | a, b = b, a + b
9 | return a + b
10 |
11 | if letter == "B":
12 | a, b = 0, 1
13 | for i in range(steps):
14 | a, b = b, a + b
15 | return a + b
16 |
17 | if letter == "C":
18 | return 2 ** steps
19 |
20 | if letter == "D":
21 | return 2 ** steps
22 |
23 | if letter == "E":
24 | return 2 ** steps
25 |
26 | ans = ""
27 |
28 | def change(word):
29 | new = ""
30 | for letter in word:
31 | if letter == "A":
32 | new += "B"
33 | elif letter == "B":
34 | new += "AB"
35 | elif letter == "C":
36 | new += "CD"
37 | elif letter == "D":
38 | new += "DC"
39 | elif letter == "E":
40 | new += "EE"
41 | return new
42 |
43 | for j in range(s, 0, -1):
44 | t = p
45 | for i in range(len(string)):
46 | x = count(string[i], j)
47 | if x >= t:
48 | string = change(string[:i+1])
49 | break
50 | else:
51 | t -= x
52 | temp = string[:p]
53 | ans = f"{temp.count('A')} {temp.count('B')} {temp.count('C')} {temp.count('D')} {temp.count('E')}"
54 | print(ans)
--------------------------------------------------------------------------------
/2008/bio2008.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 |
3 | def move1(_string):
4 | temp = _string[1:4]
5 | _string = temp + _string[0] + _string[4:]
6 | return _string
7 |
8 | def move2(_string):
9 | temp = _string[3:6]
10 | _string = _string[:3] + _string[6] + temp
11 | return _string
12 |
13 | def move3(_string):
14 | temp = _string[:3]
15 | _string = _string[3] + temp + _string[4:]
16 | return _string
17 |
18 | def move4(_string):
19 | temp = _string[4:]
20 | _string = _string[:3] + temp + _string[3]
21 | return _string
22 |
23 | def bfs():
24 | wanted = "1234567"
25 | seen = set()
26 | queue = deque()
27 | n = input()
28 | if n == wanted: return 0
29 | queue.append([n, 0])
30 | seen.add(n)
31 | while queue:
32 | cur, moves_taken = queue.popleft()
33 | new = move1(cur)
34 | if new not in seen:
35 | if new == wanted:
36 | return moves_taken + 1
37 | queue.append([new, moves_taken + 1])
38 | seen.add(new)
39 |
40 | new = move2(cur)
41 | if new not in seen:
42 | if new == wanted:
43 | return moves_taken + 1
44 | queue.append([new, moves_taken + 1])
45 | seen.add(new)
46 |
47 | new = move3(cur)
48 | if new not in seen:
49 | if new == wanted:
50 | return moves_taken + 1
51 | queue.append([new, moves_taken + 1])
52 | seen.add(new)
53 |
54 | new = move4(cur)
55 | if new not in seen:
56 | if new == wanted:
57 | return moves_taken + 1
58 | queue.append([new, moves_taken + 1])
59 | seen.add(new)
60 |
61 |
62 | NAME = ""
63 | SCHOOL = ""
64 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
65 | print(bfs())
--------------------------------------------------------------------------------
/2009/bio2009q1.py:
--------------------------------------------------------------------------------
1 | def solve(word):
2 | n = len(word)
3 | possible = ["ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE"]
4 | for digit in possible:
5 | pos = 0
6 | c = len(digit)
7 | for i in range(n):
8 | if word[i]==digit[pos]:
9 | pos += 1
10 | if pos==c:
11 | print(possible.index(digit) + 1)
12 | exit(0)
13 | print("NO")
14 |
15 | if __name__=="__main__":
16 | NAME = ""
17 | SCHOOL = ""
18 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
19 | word = input()
20 | solve(word)
21 |
--------------------------------------------------------------------------------
/2009/bio2009q2.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 |
3 | blocks = [[],[],[],[]] # Each sublist is a column
4 | for _ in range(4):
5 | row = input()
6 | for i in range(4):
7 | blocks[i].append(row[i])
8 |
9 | original = [i.copy() for i in blocks]
10 |
11 | pos = [3, 3, 3, 3]
12 |
13 | def remove_blocks(id_list): # [x1, y1], ...]
14 | id_list.sort(key=lambda p: p[1], reverse=True)
15 | for id in id_list:
16 | if len(blocks[id[0]])==1:
17 | blocks[id[0]] = []
18 | else:
19 | del blocks[id[0]][id[1]]
20 |
21 | def fill_column(column_id):
22 | blocks[column_id].reverse()
23 | for i in range(len(blocks[column_id]), 4):
24 | blocks[column_id].append(original[column_id][pos[column_id]])
25 | pos[column_id] -= 1
26 | if pos[column_id] < 0:
27 | pos[column_id]=3
28 | blocks[column_id].reverse()
29 |
30 | def bfs():
31 | global ans
32 | total = 1
33 | seen = set()
34 | points = 0
35 | to_be_deleted = []
36 | for i in range(4):
37 | for j in range(4):
38 | if (i,j) not in seen:
39 | cur = blocks[i][j]
40 | queue = deque()
41 | queue.append((i,j))
42 | points = 0
43 | temp = [(i,j)]
44 | while queue:
45 | xy = queue.popleft()
46 | points += 1
47 | seen.add(xy)
48 | if xy[0] < 3:
49 | if (xy[0]+1, xy[1]) not in seen:
50 | if blocks[xy[0]+1][xy[1]] == cur:
51 | queue.append((xy[0]+1, xy[1]))
52 | temp.append((xy[0]+1, xy[1]))
53 | seen.add((xy[0]+1, xy[1]))
54 | if xy[1] < 3:
55 | if (xy[0], xy[1]+1) not in seen:
56 | if blocks[xy[0]][xy[1]+1] == cur:
57 | queue.append((xy[0], xy[1]+1))
58 | temp.append((xy[0], xy[1]+1))
59 | seen.add((xy[0], xy[1]+1))
60 |
61 | if xy[0]:
62 | if (xy[0]-1, xy[1]) not in seen:
63 | if blocks[xy[0] - 1][xy[1]] == cur:
64 | queue.append((xy[0]-1, xy[1]))
65 | temp.append((xy[0]-1, xy[1]))
66 | seen.add((xy[0]-1, xy[1]))
67 | if xy[1]:
68 | if (xy[0], xy[1]-1) not in seen:
69 | if blocks[xy[0]][xy[1]-1] == cur:
70 | queue.append((xy[0], xy[1]-1))
71 | temp.append((xy[0], xy[1]-1))
72 | seen.add((xy[0], xy[1]-1))
73 |
74 | if points > 1:
75 | total *= points
76 | to_be_deleted.extend(temp)
77 | if not to_be_deleted:
78 | print(ans)
79 | print("GAME OVER")
80 | exit(0)
81 | remove_blocks(to_be_deleted)
82 | for i in range(4):
83 | fill_column(i)
84 | return total if total > 1 else 0
85 |
86 |
87 | NAME = ""
88 | SCHOOL = ""
89 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
90 | ans = 0
91 |
92 | while True:
93 | N = int(input())
94 | if N == 0:
95 | exit(0)
96 | for _ in range(N):
97 | ans += bfs()
98 | print("\n".join("".join(blocks[j][i] for j in range(4)) for i in range(4)))
99 | print(ans)
--------------------------------------------------------------------------------
/2009/bio2009q3.py:
--------------------------------------------------------------------------------
1 | from functools import lru_cache
2 |
3 | @lru_cache(maxsize=None)
4 | def num_arrangements(n):
5 | if n > 9:
6 | t = 0
7 | for i in range(n-9,n):
8 | t += num_arrangements(i)
9 | return t
10 | else:
11 | return 2**(n-1) if n else 1
12 |
13 | answers = []
14 | def solve():
15 | n, query = (int(x) for x in input().split())
16 |
17 | ans = []
18 | while True:
19 | if n == 0:
20 | break
21 | for i in range(1, min(10, n+1)):
22 | c = num_arrangements(n-i)
23 | if c >= query: # Right prefix
24 | ans.append(str(i))
25 | n -= i
26 | break
27 | else:
28 | query -= c
29 | print(" ".join(ans))
30 |
31 | NAME = ""
32 | SCHOOL = ""
33 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
34 | solve()
--------------------------------------------------------------------------------
/2010/bio10q1.py:
--------------------------------------------------------------------------------
1 | from collections import defaultdict
2 | NAME = ""
3 | SCHOOL = ""
4 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
5 | n=int(input())
6 | anagram = defaultdict(int)
7 | k = n
8 | while k!=0:
9 | anagram[k%10] += 1
10 | k//=10
11 | ans = []
12 | for i in range(2,10):
13 | original = anagram.copy()
14 | new = n*i
15 | ok = True
16 | while new!=0:
17 | if not original[new%10]:
18 | ok = False
19 | break
20 | original[new%10] -= 1
21 | new//=10
22 | if ok:
23 | ans.append(str(i))
24 | print(" ".join(ans) if ans else "NO")
25 | """
26 | c = 85247910
27 | anagram2 = defaultdict(int)
28 | while c!=0:
29 | anagram2[c%10] += 1
30 | c//=10
31 | c = 85247910
32 | for i in range(2,10):
33 | if not c%i:
34 | original = anagram2.copy()
35 | new = c//i
36 | if len(str(new)) != len(str(c)):
37 | continue
38 | ok = True
39 | while new!=0:
40 | if not original[new%10]:
41 | ok = False
42 | break
43 | original[new%10] -= 1
44 | new//=10
45 | if ok:
46 | print(c//i)
47 | """
--------------------------------------------------------------------------------
/2010/bio10q2.py:
--------------------------------------------------------------------------------
1 | class Grid():
2 | def __init__(self, row1, row2, row3):
3 | self.grid = [[1 for _ in range(11)] for _ in range(11)]
4 | self.grid[4][4:7]=row1
5 | self.grid[5][4:7]=row2
6 | self.grid[6][4:7]=row3
7 |
8 | def change_value(self, number, y, x):
9 | self.grid[y][x]+=number
10 | self.grid[y][x]-=1
11 | self.grid[y][x]%=6
12 | self.grid[y][x]+=1
13 |
14 |
15 | class Dice():
16 | def __init__(self, grid): # Default values
17 | self.faces = {1: "top", 6: "bottom", 3: "left", 4: "right", 5: "front", 2: "back"}
18 | self.values = {"top": 1, "bottom": 6, "left": 3, "right": 4, "front": 5, "back": 2}
19 | self.pos = (5,5)
20 | self.grid = grid
21 | self.heading = "back"
22 | self.directions = {"front": (1,0), "right": (0,1), "back": (-1,0), "left": (0,-1)}
23 |
24 | def change_face(self, direction1, direction2):
25 | v1 = self.values[direction1]
26 | self.faces[v1]=direction2
27 |
28 | def update_values(self):
29 | for i in self.faces:
30 | self.values[self.faces[i]]=i
31 |
32 | def rotate(self, direction):
33 | if direction=="left":
34 | # Left becomes bottom, right becomes top, bottom becomes right, top becomes left
35 | self.change_face("left", "bottom")
36 | self.change_face("right", "top")
37 | self.change_face("bottom", "right")
38 | self.change_face("top", "left")
39 | elif direction=="right":
40 | self.change_face("right", "bottom")
41 | self.change_face("left", "top")
42 | self.change_face("bottom", "left")
43 | self.change_face("top", "right")
44 | elif direction=="front":
45 | self.change_face("front", "bottom")
46 | self.change_face("back", "top")
47 | self.change_face("bottom", "back")
48 | self.change_face("top", "front")
49 | elif direction=="back":
50 | self.change_face("back", "bottom")
51 | self.change_face("front", "top")
52 | self.change_face("bottom", "front")
53 | self.change_face("top", "back")
54 |
55 | self.update_values()
56 |
57 | def move(self):
58 | y, x = self.pos
59 | self.grid.change_value(self.values["top"], y, x)
60 | value = self.grid.grid[y][x]
61 | if value == 1 or value == 6: pass
62 | elif value == 3 or value == 4:
63 | self.heading = self.faces[7 - self.values[self.heading]]
64 | elif value == 2:
65 | if self.heading == "front":
66 | self.heading = "left"
67 | elif self.heading == "back":
68 | self.heading = "right"
69 | elif self.heading == "left":
70 | self.heading = "back"
71 | elif self.heading == "right":
72 | self.heading = "front"
73 | elif value == 5:
74 | if self.heading == "left":
75 | self.heading = "front"
76 | elif self.heading == "right":
77 | self.heading = "back"
78 | elif self.heading == "back":
79 | self.heading = "left"
80 | elif self.heading == "front":
81 | self.heading = "right"
82 |
83 | a, b = self.directions[self.heading]
84 | self.pos = ((self.pos[0] + a)%11, (self.pos[1] + b)%11)
85 | self.rotate(self.heading)
86 |
87 | def __str__(self):
88 | y = self.pos[0]
89 | x = self.pos[1]
90 | ans = []
91 | for j in range(y-1,y+2):
92 | temp = ""
93 | for i in range(x-1,x+2):
94 | if j>10 or i>10 or j<0 or i<0:
95 | temp += "X"
96 | else:
97 | temp += str(self.grid.grid[j][i])
98 | ans.append(temp)
99 | return "\n".join(ans)
100 |
101 |
102 | NAME = ""
103 | SCHOOL = ""
104 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
105 |
106 | rows = [[int(x) for x in input().split()] for _ in range(3)]
107 | grid = Grid(rows[0], rows[1], rows[2])
108 | dice = Dice(grid)
109 |
110 | while True:
111 | n = int(input())
112 | if n==0:
113 | break
114 | for _ in range(n):
115 | dice.move()
116 | print(dice)
--------------------------------------------------------------------------------
/2011/bio2011q1.py:
--------------------------------------------------------------------------------
1 | NAME = ""
2 | SCHOOL = ""
3 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
4 |
5 | a, b, n = input().split()
6 | n = int(n)
7 |
8 | if n == 1:
9 | print(a)
10 | exit(0)
11 | if n == 2:
12 | print(b)
13 | exit(0)
14 |
15 | t = ord("A")-1
16 | x, y = ord(a)-t, ord(b)-t
17 |
18 | seen = {}
19 | for i in range(2,n):
20 | x, y = y, x+y
21 | if y>26:
22 | y -= 26
23 | """
24 | if (x,y) in seen:
25 | print(i)
26 | print(seen[(x,y)])
27 | break
28 | else:
29 | seen[(x,y)]=i
30 | """
31 |
32 |
33 | print(chr(y+t))
34 | # print(chr(t+ord("X")-ord("F")))
35 | ## R
36 | # print(chr(t+26+ord("H")-ord("Q")))
37 | ## Q
38 |
39 | # print(10**15 % 84)
40 | ## 74
41 | # C C 75 = K
--------------------------------------------------------------------------------
/2011/bio2011q2.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 |
3 | NAME = ""
4 | SCHOOL = ""
5 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
6 |
7 | values = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"]
8 | suits = ["C", "H", "S", "D"]
9 | before_dealing = deque()
10 | for s in suits:
11 | for i in values:
12 | before_dealing.append(i+s)
13 |
14 | piles = []
15 | abcdef = [int(x) for x in input().split()]
16 |
17 | i = 0
18 | seen = set()
19 | while before_dealing:
20 | for _ in range(abcdef[i]-1):
21 | before_dealing.append(before_dealing.popleft())
22 | piles.append([1, before_dealing.popleft()])
23 | i += 1
24 | i %= 6
25 |
26 | print(f"{piles[0][1]} {piles[-1][1]}")
27 |
28 | original = [piles[i].copy() for i in range(len(piles))]
29 | # print(original)
30 |
31 | def move(index1, index2): # Move pile one onto pile 2
32 | piles[index2][0] += piles[index1][0]
33 | piles[index2][1] = piles[index1][1]
34 | del piles[index1]
35 |
36 | def check_validity(index1, index2):
37 | if index2 < 0:
38 | return False
39 | if piles[index1][1][0] == piles[index2][1][0] or piles[index1][1][1] == piles[index2][1][1]:
40 | return True
41 | return False
42 |
43 | game_continue = True
44 | while game_continue:
45 | if len(piles)==1:
46 | break
47 | i = len(piles)-1
48 | while True:
49 | if i == 0: # No valid moves
50 | game_continue=False
51 | break
52 |
53 | # Check adjacent pile
54 | if check_validity(i, i-1):
55 | move(i, i-1)
56 | break
57 |
58 | # Check separated pile
59 | elif check_validity(i, i-3):
60 | move(i,i-3)
61 | break
62 |
63 | i -= 1
64 |
65 | print(f"{len(piles)} {piles[0][1]}")
66 |
67 | # print(piles)
68 | piles = [original[i].copy() for i in range(len(original))]
69 | # print(piles)
70 |
71 | while True:
72 | if len(piles)==1:
73 | break
74 | largest = 0
75 | indices = []
76 | for i in range(len(piles)-1, 0, -1):
77 | if check_validity(i, i-1):
78 | c = largest
79 | largest = max(largest, piles[i][0] + piles[i-1][0])
80 | if c!=largest:
81 | indices = [i, i-1]
82 | if check_validity(i, i-3):
83 | c = largest
84 | largest = max(largest, piles[i][0] + piles[i-3][0])
85 | if c!=largest:
86 | indices = [i, i-3]
87 | if not indices:
88 | break
89 | move(indices[0], indices[1])
90 |
91 | print(f"{len(piles)} {piles[0][1]}")
92 |
93 | piles = [original[i].copy() for i in range(len(original))]
94 | # piles = [[1, "AD"], [3, "8S"], [1, "8D"], [2, "4S"], [1, "TH"], [2, "KD"], [2, "4D"], [1, "TC"]]
95 |
96 | def find_valid(index1, index2):
97 | temp = [piles[i].copy() for i in range(len(piles))]
98 | temp[index2][0] += temp[index1][0]
99 | temp[index2][1] = temp[index1][1]
100 | del temp[index1]
101 |
102 | moves = 0
103 |
104 | def valid(i1, i2):
105 | if i2 < 0:
106 | return False
107 | if temp[i1][1][0] == temp[i2][1][0] or temp[i1][1][1] == temp[i2][1][1]:
108 | return True
109 | return False
110 |
111 | for i in range(len(temp)-1, 0, -1):
112 | if valid(i, i-1):
113 | moves += 1
114 | if valid(i, i-3):
115 | moves += 1
116 |
117 | return moves
118 |
119 | while True:
120 | if len(piles)==1:
121 | break
122 | largest = 0
123 | indices = []
124 | possible = False
125 | for i in range(len(piles)-1, 0, -1):
126 | if check_validity(i, i-1):
127 | possible = True
128 | c = largest
129 | largest = max(largest, find_valid(i, i-1))
130 | if c!=largest or largest==0:
131 | indices = [i, i-1]
132 | if check_validity(i, i-3):
133 | possible = True
134 | c = largest
135 | largest = max(largest, find_valid(i, i-3))
136 | if c!=largest or largest==0:
137 | indices = [i, i-3]
138 | if not indices and not possible:
139 | break
140 | move(indices[0], indices[1])
141 |
142 | print(f"{len(piles)} {piles[0][1]}")
--------------------------------------------------------------------------------
/2011/bio2011q3.py:
--------------------------------------------------------------------------------
1 | from bisect import bisect_left
2 |
3 | NAME = ""
4 | SCHOOL = ""
5 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
6 | n = int(input())
7 | import time
8 | start = time.time()
9 |
10 | upside_down_numbers = [5, 19, 28, 37, 46, 55, 64, 73, 82, 91]
11 | if n<=10:
12 | print(upside_down_numbers[n-1])
13 | exit(0)
14 |
15 | n -= 10
16 | min = 10
17 | while True:
18 | new = []
19 | pos = bisect_left(upside_down_numbers, min)
20 | min *= 10
21 | new = []
22 | k = 9 * pos
23 | for j in range(1,10):
24 | for i in range(pos):
25 | new.append(j*min + upside_down_numbers[i]*10 + 10-j)
26 | n -= 1
27 | if n==0:
28 | print(new[-1])
29 | print(time.time()-start)
30 | exit(0)
31 | upside_down_numbers = [upside_down_numbers[i] for i in range(pos, len(upside_down_numbers))] + new
--------------------------------------------------------------------------------
/2012/bio2012q1.py:
--------------------------------------------------------------------------------
1 | from collections import defaultdict
2 |
3 | def solve():
4 | n = int(input())
5 | ans = 1
6 | for i in range(2, int(n**0.5)+1):
7 | if not n%i:
8 | while not n%i:
9 | n //= i
10 | ans *= i
11 | if not n:
12 | return ans
13 | if ans == 1: # Prime
14 | return n
15 | return ans
16 |
17 | def c(n):
18 | ans = 1
19 | for i in range(2, int(n ** 0.5) + 1):
20 | if not n % i:
21 | while not n % i:
22 | n //= i
23 | ans *= i
24 | if not n:
25 | return ans
26 | if ans == 1: # Prime
27 | return n
28 | return ans
29 |
30 | if __name__ == "__main__":
31 | NAME = ""
32 | SCHOOL = ""
33 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
34 | print(solve())
35 | # print("10, 20, 40, 50, 80, 100, 160, 200, 250, 320")
36 | seen = defaultdict(int)
37 | for i in range(1,1000001):
38 | if not i%10000:
39 | print(i)
40 | seen[c(i)] += 1
41 | occurences = 0
42 | largest = 0
43 | for x in seen:
44 | if seen[x] > occurences:
45 | largest = x
46 | occurences = seen[x]
47 | print(largest)
--------------------------------------------------------------------------------
/2012/bio2012q3.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 | # import time
3 |
4 | digit_words = {1: "ONE", 2: "TWO", 3: "THREE", 4: "FOUR", 5: "FIVE", 6: "SIX",
5 | 7: "SEVEN", 8: "EIGHT", 9: "NINE", 0: "ZERO"}
6 | words = {"ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "ZERO"}
7 | letters = ["O", "N", "E", "T", "W", "H", "R", "F", "U", "I", "V", "S", "X", "G", "Z"]
8 |
9 | def number_to_word(n):
10 | if n==-1:
11 | return [""]
12 | t = []
13 | while n:
14 | t.append(digit_words[n % 10])
15 | n //= 10
16 | return t
17 |
18 | def solve():
19 | answers = []
20 | for _ in range(3):
21 | s, f = (int(x) for x in input().split())
22 | # start = time.time()
23 | ts, tf = str(s), str(f)
24 | tts = ts
25 | for digit in tts:
26 | if digit in tf and digit in ts:
27 | tf = tf.replace(digit, "")
28 | ts = ts.replace(digit, "")
29 | s, f = int(ts) if ts else -1, int(tf) if tf else -1
30 | a, b = number_to_word(s), number_to_word(f)
31 | print(bfs("".join(a[::-1]), "".join(b[::-1])))
32 | # print(time.time()-start)
33 |
34 | def count(start): # Returns tuple state
35 | return tuple((start.count("O"), start.count("N"),
36 | start.count("E"), start.count("T"),
37 | start.count("W"), start.count("H"),
38 | start.count("R"), start.count("F"),
39 | start.count("U"), start.count("I"),
40 | start.count("V"), start.count("S"),
41 | start.count("X"), start.count("G"),
42 | start.count("Z")))
43 |
44 | numbers = [count("".join(number_to_word(i)[::-1])) for i in range(1,1000)]
45 |
46 | def find_all_states(state):
47 | states = []
48 | for i in range(999):
49 | if sum(abs(numbers[i][j]-state[j]) for j in range(15)) < 6:
50 | states.append(numbers[i])
51 | return states
52 |
53 | def bfs(start, target):
54 | # Numbers are made of O, N, E, T, W, H, R, F, U, I, V, S, X, G, Z
55 | start_state = count(start)
56 | end_state = count(target)
57 | seen = set()
58 | queue = deque()
59 | queue.append([start_state,0])
60 | while queue:
61 | cur = queue.popleft()
62 | if cur[0] in seen:
63 | continue
64 | seen.add(cur[0])
65 | new_states = find_all_states(cur[0])
66 | for i in range(len(new_states)):
67 | if new_states[i]==end_state:
68 | return cur[1]+1
69 | else:
70 | if new_states[i] not in seen:
71 | queue.append([new_states[i], cur[1]+1])
72 | # print(new_states[i])
73 |
74 |
75 | if __name__ == "__main__":
76 | NAME = ""
77 | SCHOOL = ""
78 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
79 | solve()
--------------------------------------------------------------------------------
/2013/bio2013q3.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 |
3 | grid = [[0 for _ in range(5)] for _ in range(5)]
4 |
5 | def solve():
6 | pos_list = convert_to_num(input())
7 | for y,x, n in pos_list:
8 | grid[y][x] += n
9 | print(bfs(convert_to_string(grid)))
10 |
11 |
12 | def convert_to_num(string):
13 | lst = []
14 | for letter in string:
15 | if letter.isupper():
16 | ans = ord(letter) - ord("A")
17 | lst.append([ans // 5, ans % 5, 2])
18 | else:
19 | ans = ord(letter) - ord("a")
20 | lst.append([ans // 5, ans % 5, 1])
21 | return lst
22 |
23 | def convert_to_string(array):
24 | ans = ""
25 | for i in range(5):
26 | for j in range(5):
27 | if not array[i][j]:
28 | continue
29 | if array[i][j]==1:
30 | ans += chr(i*5+j + ord("a"))
31 | else:
32 | ans += chr(i*5+j + ord("A"))
33 | return ans
34 |
35 | def light(array, position, presses):
36 | y, x = position // 5, position % 5
37 | array[y][x] = (array[y][x] + presses) % 3
38 | if y: array[y-1][x] = (array[y-1][x] + presses) % 3
39 | if x: array[y][x-1] = (array[y][x-1] + presses) % 3
40 | if y != 4: array[y+1][x] = (array[y+1][x] + presses) % 3
41 | if x != 4: array[y][x+1] = (array[y][x+1] + presses) % 3
42 |
43 | def bfs(string):
44 | start = string
45 | prev = {string: ""}
46 | prev_action = {string: ""}
47 | queue = deque()
48 | queue.append(string)
49 | while queue:
50 | cur = queue.popleft()
51 | for i in range(25):
52 | for j in range(1,3):
53 | x = [[0 for _ in range(5)] for _ in range(5)]
54 | pos_list = convert_to_num(cur)
55 | for y, z, n in pos_list:
56 | x[y][z] += n
57 | light(x, i, j)
58 | new = convert_to_string(x)
59 | if new not in prev:
60 | if new == "":
61 | actions = chr(i + ord("a")) if j==1 else chr(i + ord("A"))
62 | while cur != start:
63 | pos, presses = prev_action[cur]
64 | if presses==1:
65 | actions += chr(pos + ord("a"))
66 | else:
67 | actions += chr(pos + ord("A"))
68 | cur = prev[cur]
69 | return actions[::-1]
70 | else:
71 | prev[new] = cur
72 | prev_action[new] = (i, j)
73 | queue.append(new)
74 | return "IMPOSSIBLE"
75 |
76 | if __name__ == "__main__":
77 | NAME = ""
78 | SCHOOL = ""
79 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
80 | solve()
--------------------------------------------------------------------------------
/2014/bio14q1.py:
--------------------------------------------------------------------------------
1 | import time
2 | from bisect import bisect_left, bisect_right
3 |
4 | def lucky(lst, first):
5 | for j in range(len(lst)-1, -1, -1):
6 | if (j-1) and not (j+1)%first:
7 | del lst[j]
8 | return lst
9 |
10 | if __name__ == '__main__':
11 | NAME = ""
12 | SCHOOL = ""
13 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
14 | n = int(input())
15 | start = time.time()
16 | odd = [2*i+1 for i in range(5200)]
17 | first_number = odd[1]
18 | index = 1
19 | while first_number < n and index<16:
20 | lucky(odd, first_number)
21 | index += 1
22 | first_number = odd[index]
23 |
24 | print(f"{odd[bisect_left(odd, n)-1]} {odd[bisect_right(odd, n)]}")
25 |
26 | print(time.time()-start)
27 |
--------------------------------------------------------------------------------
/2014/bio14q2.py:
--------------------------------------------------------------------------------
1 |
2 | redTiles = {1: [[1,1,3,4,5,6],[(-1,0),(1,0),(1,0),(1,0),(-1,0),(-1,0)]], 2: [[2,2,3,4,5,6],[(0,-1),(0,1),(0,1),(0,-1),(0,-1),(0,1)]],
3 | 3: [[1,2,4,5,5,6],[(-1,0),(0,-1),(0,-1),(-1,0),(0,-1),(-1,0)]], 4: [[1,2,3,5,6,6],[(-1,0),(0,1),(0,1),(-1,0),(0,1),(-1,0)]],
4 | 5: [[1,2,3,3,4,6],[(1,0),(0,-1),(1,0),(0,1),(1,0),(0,1)]], 6: [[1,2,3,4,4,5],[(1,0),(0,-1),(1,0),(1,0),(0,-1),(0,-1)]]}
5 |
6 | greenTiles = {2: [[2,2,5,6,3,4],[(-1,0),(1,0),(1,0),(1,0),(-1,0),(-1,0)]], 1: [[1,1,5,6,3,4],[(0,-1),(0,1),(0,1),(0,-1),(0,-1),(0,1)]],
7 | 5: [[2,1,6,3,3,4],[(-1,0),(0,-1),(0,-1),(-1,0),(0,-1),(-1,0)]], 6: [[2,1,5,3,4,4],[(-1,0),(0,1),(0,1),(-1,0),(0,1),(-1,0)]],
8 | 3: [[2,1,5,5,6,4],[(1,0),(0,-1),(1,0),(0,1),(1,0),(0,1)]], 4: [[2,1,5,6,6,3],[(1,0),(0,-1),(1,0),(1,0),(0,-1),(0,-1)]]}
9 |
10 | r_total = 0
11 | g_total = 0
12 | found = False
13 |
14 |
15 | def RedConnect(pos, start, used, points=0):
16 | currentUsed = used.copy()
17 | global r_total, found
18 | if pos==start and points>3:
19 | r_total += points/sum(1 for i in used if grid[i[0]][i[1]]==5 )
20 | found = True
21 | return
22 | row, column = pos[0], pos[1]
23 | directions = redTiles[grid[row][column]][1]
24 | wantedTiles = redTiles[grid[row][column]][0]
25 | connections = 0
26 | for k in range(len(directions)):
27 | up, right = directions[k]
28 | used = currentUsed.copy()
29 | try:
30 | if grid[row + up][column + right] == wantedTiles[k] and row +up >=0 and column + right >=0:
31 | connections += 1
32 | newTile = [row + up,column + right]
33 | if newTile not in used or (newTile==start and points > 2):
34 | if newTile not in used:
35 | used.append([row, column])
36 | RedConnect(newTile, start,used,points + 1)
37 | if found:
38 | break
39 | except IndexError:
40 | pass
41 |
42 | def GreenConnect(pos, start, used, points=0):
43 | currentUsed = used.copy()
44 | global g_total, found
45 | if pos==start and points>3:
46 | g_total += points/sum(1 for i in used if grid[i[0]][i[1]]==3 )
47 | found = True
48 | return
49 | row, column = pos[0], pos[1]
50 | directions = greenTiles[grid[row][column]][1]
51 | wantedTiles = greenTiles[grid[row][column]][0]
52 | connections = 0
53 | for k in range(len(directions)):
54 | up, right = directions[k]
55 | used = currentUsed.copy()
56 | try:
57 | if grid[row + up][column + right] == wantedTiles[k] and row +up >=0 and column + right >=0:
58 | connections += 1
59 | newTile = [row + up,column + right]
60 | if newTile not in used or (newTile==start and points > 2):
61 | if newTile not in used:
62 | used.append([row, column])
63 | GreenConnect(newTile, start,used,points + 1)
64 | if found:
65 | break
66 | except IndexError:
67 | pass
68 |
69 |
70 | NAME = ""
71 | SCHOOL = ""
72 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
73 | n = int(input())
74 | grid = [[int(x) for x in input().split()] for _ in range(n)]
75 |
76 | # Red Player
77 | for row in range(n-1):
78 | for column in range(n-1):
79 | if grid[row][column] != 5:
80 | continue
81 | found = False
82 | RedConnect([row, column], [row, column],[])
83 |
84 |
85 | # Green Player
86 | for row in range(n-1):
87 | for column in range(n-1):
88 | if grid[row][column] != 3:
89 | continue
90 | found = False
91 | GreenConnect([row, column], [row, column],[])
92 |
93 | print(f"{int(r_total)} {int(g_total)}")
94 |
--------------------------------------------------------------------------------
/2014/bio2014q3.py:
--------------------------------------------------------------------------------
1 | import math
2 | from functools import lru_cache
3 | @lru_cache(maxsize=None)
4 | def comb(n, k):
5 | return math.factorial(n) // math.factorial(k) // math.factorial(n - k)
6 |
7 |
8 | NAME = ""
9 | SCHOOL = ""
10 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
11 | n = int(input())
12 |
13 | alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
14 |
15 |
16 | def build(n, targetLen, ans=""):
17 | if targetLen == 0:
18 | return ans
19 | start = (alpha.index(ans[-1]) + 1) if ans else 0
20 | for letter in range(start, 36):
21 |
22 | can = comb(36 - (letter + 1), targetLen - 1)
23 | print(can)
24 |
25 | if can >= n:
26 | return build(n, targetLen - 1, ans + alpha[letter]) # Right prefix
27 | n -= can
28 |
29 |
30 | targLen = 1
31 | while comb(36, targLen) < n:
32 | n -= comb(36, targLen)
33 | targLen += 1
34 | print(n)
35 |
36 | print(build(n, targLen))
--------------------------------------------------------------------------------
/2015/bio15q1.py:
--------------------------------------------------------------------------------
1 | string = input()
2 |
3 | def block_palindrome(string):
4 | blocks = 0
5 | for i in range(1, len(string)//2+1):
6 | if (string[:i] == string[-i:]):
7 | blocks += 1 + block_palindrome(string[i:-i])
8 | return blocks
9 |
10 | NAME = ""
11 | SCHOOL = ""
12 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
13 | print(block_palindrome(string))
14 |
--------------------------------------------------------------------------------
/2015/bio15q2.py:
--------------------------------------------------------------------------------
1 | NAME = ""
2 | SCHOOL = ""
3 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
4 | a, c, m = (int(x) for x in input().split())
5 | r = 0
6 |
7 | class Grid():
8 | def __init__(self):
9 | self.grid = [[0 for _ in range(10)] for __ in range(10)]
10 |
11 | def place(self, x,y):
12 | self.grid[9-y][x] = 1
13 |
14 | def valid(self, x,y):
15 | try:
16 | if self.grid[9-y][x]:
17 | return False
18 | # If that square is not on the board, it isn't valid
19 | except IndexError:
20 | return False
21 | try:
22 | if self.grid[9-y][x-1]:
23 | return False
24 | except IndexError: pass
25 | try:
26 | if self.grid[9-y][x+1]:
27 | return False
28 | except IndexError: pass
29 | try:
30 | if self.grid[8-y][x-1]:
31 | return False
32 | except IndexError: pass
33 | try:
34 | if self.grid[8-y][x+1]:
35 | return False
36 | except IndexError: pass
37 | try:
38 | if self.grid[8-y][x]:
39 | return False
40 | except IndexError: pass
41 | try:
42 | if self.grid[10-y][x]:
43 | return False
44 | except IndexError: pass
45 | try:
46 | if self.grid[10-y][x+1]:
47 | return False
48 | except IndexError: pass
49 | try:
50 | if self.grid[10-y][x-1]:
51 | return False
52 | except IndexError: pass
53 |
54 | return True
55 |
56 | toPlace = [4,3,3,2,2,2,1,1,1,1]
57 | board = Grid()
58 |
59 | for ship in toPlace:
60 | valid = False
61 | while True:
62 | r = (a*r+c)%m
63 |
64 | x = r%10
65 | y = (r%100)//10
66 | r = (a*r+c)%m
67 | d = r%2
68 | direction = "V" if d else "H"
69 | ty = y
70 | tx = x
71 | b = False
72 | for _ in range(ship):
73 | if board.valid(tx, ty):
74 | if d:
75 | ty += 1
76 | else:
77 | tx += 1
78 | else:
79 | b = True
80 | break
81 | if b:
82 | continue
83 | ty = y
84 | tx = x
85 | for _ in range(ship):
86 | board.place(tx,ty)
87 | if d:
88 | ty += 1
89 | else:
90 | tx += 1
91 |
92 | print(f"{x} {y} {direction}")
93 | break
94 |
--------------------------------------------------------------------------------
/2015/bio2015q3.py:
--------------------------------------------------------------------------------
1 | # 30 / 32
2 |
3 | """
4 | from functools import lru_cache
5 |
6 | @lru_cache(maxsize=None)
7 | def factorial(n):
8 | if n==0:
9 | return 1
10 | else:
11 | return n*factorial(n-1)
12 |
13 | a, b, c, d, n = (int(x) for x in input().split())
14 | Sum = a+b+c+d
15 | temp = [a,b,c,d]
16 |
17 | total = factorial(Sum)/factorial(a)/factorial(b)/factorial(c)/factorial(d)
18 |
19 | ans = ""
20 |
21 | while any(temp):
22 | c = total/sum(temp)
23 | pos = n/c
24 |
25 | k = 0
26 | for i in range(len(temp)):
27 | if temp[i]==0:
28 | k += 1
29 | if pos>temp[i]:
30 | pos -= temp[i]
31 | else:
32 | break
33 | ans += "ABCD"[i]
34 |
35 | n -= c*sum(temp[:i])
36 | temp[i] -= 1
37 | total = factorial(sum(temp))
38 | for k in temp:
39 | total /= factorial(k)
40 |
41 | print(ans)
42 | """
43 |
44 | from functools import lru_cache
45 |
46 | @lru_cache(maxsize=None)
47 | def factorial(n):
48 | if n==0:
49 | return 1
50 | else:
51 | return n*factorial(n-1)
52 | def total_ways(a, b, c, d):
53 | return factorial(a+b+c+d)//(factorial(a)*factorial(b)*factorial(c)*factorial(d))
54 |
55 | def g(a, b, c, d, n):
56 | if a==0 and b==0 and c==0 and d==0:
57 | return ''
58 | ways=total_ways(a, b, c, d)
59 |
60 | if n <= (ways*a)//(a+b+c+d) and a>0: ##letter is 'A'
61 | return 'A'+g(a-1, b, c, d, n)
62 |
63 | if n <= (ways*(a+b))//(a+b+c+d) and b>0: ##letter is 'B'
64 | return 'B'+g(a, b-1, c, d, n-(ways*a)//(a+b+c+d))
65 |
66 | if n <= (ways*(a+b+c))//(a+b+c+d) and c>0: ##letter is 'C'
67 | return 'C'+g(a, b, c-1, d, n-(ways*(a+b))//(a+b+c+d))
68 |
69 | else: ##letter is 'D'
70 | return 'D'+g(a, b, c, d-1, n-(ways*(a+b+c))//(a+b+c+d))
71 |
72 | NAME = ""
73 | SCHOOL = ""
74 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
75 | a, b, c, d, n = (int(x) for x in input().split())
76 |
77 | print(g(a, b, c, d, n))
78 |
--------------------------------------------------------------------------------
/2016/bio16q1.py:
--------------------------------------------------------------------------------
1 | def fraction(promenade):
2 | l, m = 1, 0
3 | r, s = 0, 1
4 |
5 | for i in range(len(promenade)):
6 | if promenade[i]=="L":
7 | l, m = l+r, s+m
8 | else:
9 | r, s = l+r, s+m
10 |
11 | print(f"{l+r}/{m+s}")
12 |
13 | def _1b(): # LRL + LLLL = 4/5
14 | print("LRRR")
15 |
16 | def _1c():
17 | print("999,999 Ls and 0 Rs")
18 |
19 | def _1d():
20 | print("""No none do. The promenade before any choices has l,r,m,s equal to 1,0,0,1 respectively.
21 | When the next decision is an 'L', l=l+r and m=s+m; when it is 'R', r=l+r, s=s+m.
22 | Since both of these choices only add positive (including 0) integers together (since l,r,m,s are originally positive):
23 | l,r,m,s are always positive for any promenade. So every promenade of form (l+r)/(m+s) is positive.""")
24 |
25 | if __name__=='__main__':
26 | NAME = ""
27 | SCHOOL = ""
28 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
29 | promenade = input()
30 | fraction(promenade)
--------------------------------------------------------------------------------
/2016/bio16q2.py:
--------------------------------------------------------------------------------
1 | from collections import defaultdict
2 | squares = defaultdict(int)
3 |
4 | def pos2d(pos1d):
5 | pos1d -= 1
6 | return (pos1d//5, pos1d%5)
7 |
8 | def migrate(pos2d):
9 | squares[pos2d] -= 4
10 | y, x = pos2d
11 | squares[(y+1, x)] += 1
12 | while squares[(y+1, x)] > 3:
13 | migrate((y+1,x))
14 | squares[(y-1, x)] += 1
15 | while squares[(y-1, x)] > 3:
16 | migrate((y-1,x))
17 | squares[(y, x+1)] += 1
18 | while squares[(y, x+1)] > 3:
19 | migrate((y,x+1))
20 | squares[(y, x-1)] += 1
21 | while squares[(y, x-1)] > 3:
22 | migrate((y,x-1))
23 |
24 | def step(pos1d):
25 | pos = pos2d(pos1d)
26 | squares[pos] += 1
27 | while squares[pos]>3:
28 | migrate(pos)
29 |
30 | def _2b():
31 | print(7) # WRONG 16
32 |
33 | def _2c():
34 | # 6,8,11,16, 18,21,1, 3
35 | print("6 3 8")
36 | print("2 3 5")
37 | starts = [1,3,6,8,11,16,18,21]
38 | total = 0
39 | for start in starts:
40 | for i in range(25):
41 | for j in range(25):
42 | if i==j:
43 | continue
44 | for k in range(25):
45 | seen = set()
46 | if k==j or k==i:
47 | continue
48 | seen.add(start)
49 | seen.add((start+i)%25)
50 | seen.add((start+i+j)%25)
51 | seen.add((start+i+j+k)%25)
52 | seen.add((start+i*2+j+k)%25)
53 | seen.add((start+i*2+j*2+k)%25)
54 | seen.add((start+i*2+j*2+k*2)%25)
55 | seen.add((start+i*3+j*2+k*2)%25)
56 | for s in starts:
57 | if s not in seen:
58 | total -= 1
59 | break
60 | total += 1
61 | print(total)
62 |
63 | def _2d():
64 | print("""No you cannot always determine the landscape. This is because of the possibility of multiple migrations.
65 | For example take the end landscape, given that the person was added to position 8:
66 | 0 1 1 0 0
67 | 1 0 1 1 0
68 | 0 1 1 0 0
69 | 0 0 0 0 0
70 | 0 0 0 0 0
71 | The original landscape could have been either:
72 | 0 0 0 0 0
73 | 0 3 3 0 0
74 | 0 0 0 0 0
75 | 0 0 0 0 0
76 | 0 0 0 0 0
77 | or
78 | 0 1 1 0 0
79 | 1 0 0 1 0
80 | 0 1 1 0 0
81 | 0 0 0 0 0
82 | 0 0 0 0 0""")
83 |
84 | if __name__=='__main__':
85 | NAME = ""
86 | SCHOOL = ""
87 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
88 | p, s, n = (int(x) for x in input().split())
89 | seq = [int(x) for x in input().split()]
90 | done = False
91 |
92 | while not done:
93 | for pos in seq:
94 | step(p)
95 | p += pos
96 | p-=1
97 | p %= 25
98 | p+=1
99 | n -= 1
100 | if n==0:
101 | done=True
102 | break
103 | for i in range(5):
104 | to_print = []
105 | for j in range(5):
106 | to_print.append(str(squares[(i,j)]))
107 | print(" ".join(to_print))
--------------------------------------------------------------------------------
/2016/bio16q3v2.py:
--------------------------------------------------------------------------------
1 | import pickle
2 |
3 | coins = [- 2**i for i in range(25)]
4 | coins2 = [-i for i in coins]
5 | def solve(start, end):
6 | len_primes = len(primes)
7 | lst = [0 for _ in range(len_primes)]
8 | lst[pos[start]] = 1
9 | for i in range(pos[start], pos[end]+1):
10 | c=primes[i]
11 | for coin in coins2:
12 | if coin>c:
13 | #print(c)
14 | break
15 | if c-coin not in primes:
16 | #print(c)
17 | continue
18 | if lst[pos[c-coin]]==0:
19 | continue
20 | if lst[i]==0:
21 | lst[i]=lst[pos[c-coin]]+1
22 | continue
23 | lst[i]=min(lst[pos[c-coin]]+1, lst[i])
24 | for i in range(pos[start], pos[end]+1):
25 | c=primes[i]
26 | if c==29: print(c)
27 | for coin in coins:
28 | if c==29 and coin==-2:
29 | print(c-coin)
30 | if c-coin>l-1:
31 | #print(c)
32 | continue
33 | if c-coin not in primes:
34 | #print(c)
35 | continue
36 | if lst[pos[c-coin]]==0:
37 | continue
38 | if lst[i]==0:
39 | lst[i]=lst[pos[c-coin]]+1
40 | continue
41 | lst[i]=min(lst[pos[c-coin]]+1, lst[i])
42 |
43 | print(primes)
44 | print(lst)
45 | print(lst[pos[end]])
46 |
47 |
48 | if __name__=='__main__':
49 | NAME = ""
50 | SCHOOL = ""
51 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
52 | l, p, q = (int(x) for x in input().split())
53 | with open("Primes.pickle", 'rb') as f:
54 | primes = [int(x) for x in pickle.load(f) if int(x) < l]
55 | pos = {primes[i]:i for i in range(len(primes))}
56 | solve(p,q)
57 |
--------------------------------------------------------------------------------
/2017/bio17q1.py:
--------------------------------------------------------------------------------
1 | from time import time
2 | from itertools import combinations_with_replacement as cr
3 |
4 | pairs = {"RR":"R","GG":"G","BB":"B", "RG":"B", "GR":"B","BR":"G", "RB":"G","GB":"R","BG":"R"}
5 |
6 | def finalColour(string):
7 | if len(string)==1:
8 | return string
9 | while len(string) > 1:
10 | temp = ""
11 | for i in range(len(string)-1):
12 | temp += pairs[string[i] + string[i+1]]
13 | string = temp
14 | return string
15 |
16 | def createRow(length, middle):
17 | # With chosen extreme left and right
18 | string = "B" + middle + "B"
19 |
20 | def d():
21 | colours = ["B","R","G"]
22 | i = 4
23 | while True:
24 | i += 1
25 | b = True
26 | for x in cr(colours, i-2):
27 | print("".join(x))
28 | if not b:
29 | break
30 | string = "B" + "".join(x) + "B"
31 | if finalColour(string) != "B":
32 | b= False
33 | if b:
34 | print(i)
35 | break
36 |
37 | if __name__ == '__main__':
38 | NAME = ""
39 | SCHOOL = ""
40 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
41 | while True:
42 | print("\n")
43 | string = input()
44 | # start = time()
45 | print(finalColour(string))
46 | # print(time()-start)
47 |
--------------------------------------------------------------------------------
/2017/bio17q2.py:
--------------------------------------------------------------------------------
1 | class Game():
2 |
3 | def __init__(self, p1, m1, p2, m2, t):
4 | self.board = Board()
5 | self.board.squares[0].owner
6 | self.players = [Player(p1,m1, 0), Player(p2,m2, 1)]
7 | self.turns = t
8 |
9 | def run(self):
10 | currentTurn = 0
11 | for i in range(self.turns):
12 | # t<=60 so move is always available
13 | # Player.move() not only makes move but returns True/False for whether square has been won
14 | if not self.players[currentTurn].move(self.board):
15 | currentTurn += 1
16 | currentTurn %= 2
17 | self.result()
18 |
19 | def result(self):
20 | s = ""
21 | i = 0
22 | for square in self.board.squares:
23 | s += square.owner
24 | if i%5 == 4:
25 | s += "\n"
26 | i += 1
27 | print(s)
28 | print(len(self.players[0].wonSquares),len(self.players[1].wonSquares))
29 | if all(self.board.squares[i].owner=="O" for i in range(25)):
30 | return True
31 | else: return False
32 |
33 |
34 |
35 | class Board():
36 |
37 | def __init__(self):
38 | self.squares = []
39 | for i in range(25):
40 | self.squares.append(Square())
41 |
42 | def __str__(self):
43 | return str([self.squares[i].sides for i in range(25)])
44 |
45 |
46 | class Square():
47 | def __init__(self):
48 | # [[right, top, left, bottom]]
49 | self.sides = [0,0,0,0]
50 | self.owner = "*"
51 |
52 | def completeSquare(self,turn):
53 | if all(x==1 for x in self.sides):
54 | if turn == 0:
55 | self.owner = "X"
56 | else: self.owner = "O"
57 | return True
58 |
59 | class Player():
60 | def __init__(self, position, modifier, playerNum):
61 | self.position = position
62 | self.modifier = modifier
63 | self.wonSquares = []
64 | self.playerNum = playerNum
65 |
66 | def move(self, board):
67 |
68 | self.position += self.modifier
69 | while True:
70 | if self.position > 36:
71 | self.position %= 36
72 | P = self.position - 1
73 | column = P % 6
74 | row = P // 6
75 |
76 | if self.playerNum == 1:
77 |
78 | ### Upwards line
79 | if row == 0: pass
80 | else:
81 | if column == 5:
82 | sq = board.squares[row*5 + column - 5 - 1]
83 | if sq.sides[0] == 0:
84 | sq.sides[0] = 1
85 | if sq.completeSquare(self.playerNum):
86 | self.wonSquares.append(row * 5 + column - 5 - 1)
87 | return True
88 | return False
89 | # Drawing a right line at the bottom edge
90 | elif column == 0:
91 | sq = board.squares[row*5 + column - 5]
92 | if sq.sides[2] == 0:
93 | sq.sides[2] = 1
94 | if sq.completeSquare(self.playerNum):
95 | self.wonSquares.append(row * 5 + column - 5)
96 | return True
97 | return False
98 | # Drawing a line in the centre
99 | else:
100 | new = False
101 | changed = False
102 | sq = board.squares[row*5 + column - 5 - 1]
103 | if sq.sides[0] == 0:
104 | sq.sides[0] = 1
105 | changed = True
106 | if sq.completeSquare(self.playerNum):
107 | self.wonSquares.append(row * 5 + column - 5 - 1)
108 | new = True
109 | sq = board.squares[row*5 + column - 5]
110 | if sq.sides[2] == 0:
111 | sq.sides[2] = 1
112 | changed = True
113 | if sq.completeSquare(self.playerNum):
114 | self.wonSquares.append(row * 5 + column - 5)
115 | new = True
116 | if new:
117 | return True
118 | if changed:
119 | return False
120 |
121 | # If on the left, cannot go left
122 | ### Left line
123 | if column == 0: pass
124 | else:
125 | if row == 0:
126 | sq = board.squares[row*5 + column - 1]
127 | if sq.sides[1] == 0:
128 | sq.sides[1] = 1
129 | if sq.completeSquare(self.playerNum):
130 | self.wonSquares.append(row * 5 + column - 1)
131 | return True
132 | return False
133 | # Drawing a left line at the bottom edge
134 | elif row == 5:
135 | sq = board.squares[row*5 + column - 5 - 1]
136 | if sq.sides[3] == 0:
137 | sq.sides[3] = 1
138 | if sq.completeSquare(self.playerNum):
139 | self.wonSquares.append(row * 5 + column - 5 - 1)
140 | return True
141 | return False
142 | # Drawing a line in the centre
143 | else:
144 | new = False
145 | changed = False
146 | sq = board.squares[row*5 + column - 1]
147 | if sq.sides[1] == 0:
148 | sq.sides[1] = 1
149 | changed = True
150 | if sq.completeSquare(self.playerNum):
151 | self.wonSquares.append(row * 5 + column - 1)
152 | new = True
153 | sq = board.squares[row*5 + column - 5 - 1]
154 | if sq.sides[3] == 0:
155 | sq.sides[3] = 1
156 | changed = True
157 | if sq.completeSquare(self.playerNum):
158 | self.wonSquares.append(row * 5 + column - 5 - 1)
159 | new = True
160 | if new:
161 | return True
162 | if changed:
163 | return False
164 |
165 | # If on the bottom , cannot go bottom
166 | ### Downwards line
167 | if row == 5: pass
168 | else:
169 | if column == 0:
170 | sq = board.squares[row*5 + column]
171 | if sq.sides[2] == 0:
172 | sq.sides[2] = 1
173 | if sq.completeSquare(self.playerNum):
174 | self.wonSquares.append(row * 5 + column)
175 | return True
176 | return False
177 | # Drawing a right line at the bottom edge
178 | elif column == 5:
179 | sq = board.squares[row*5 + column - 1]
180 | if sq.sides[0] == 0:
181 | sq.sides[0] = 1
182 | if sq.completeSquare(self.playerNum):
183 | self.wonSquares.append(row * 5 + column - 1)
184 | return True
185 | return False
186 | # Drawing a line in the centre
187 | else:
188 | new = False
189 | changed = False
190 | sq = board.squares[row*5 + column]
191 | if sq.sides[2] == 0:
192 | sq.sides[2] = 1
193 | changed = True
194 | if sq.completeSquare(self.playerNum):
195 | self.wonSquares.append(row * 5 + column)
196 | new = True
197 | sq = board.squares[row*5 + column - 1]
198 | if sq.sides[0] == 0:
199 | sq.sides[0] = 1
200 | changed = True
201 | if sq.completeSquare(self.playerNum):
202 | self.wonSquares.append(row * 5 + column - 1)
203 | new = True
204 | if new:
205 | return True
206 | if changed:
207 | return False
208 |
209 | ### Line to the right
210 | # Cant draw a line from right edge
211 | if column == 5: pass
212 | else:
213 | # Drawing a right line at the top edge
214 | if row == 0:
215 | sq = board.squares[row*5 + column]
216 | sq.sides
217 | if sq.sides[1] == 0:
218 | sq.sides[1] = 1
219 | if sq.completeSquare(self.playerNum):
220 | self.wonSquares.append(row * 5 + column)
221 | return True
222 | return False
223 | # Drawing a right line at the bottom edge
224 | elif row == 5:
225 | sq = board.squares[row*5 + column - 5]
226 | if sq.sides[3] == 0:
227 | sq.sides[3] = 1
228 | if sq.completeSquare(self.playerNum):
229 | self.wonSquares.append(row * 5 + column - 5)
230 | return True
231 | return False
232 | # Drawing a line in the centre
233 | else:
234 | new = False
235 | changed = False
236 | sq = board.squares[row*5 + column - 5]
237 | if sq.sides[3] == 0:
238 | sq.sides[3] = 1
239 | changed = True
240 | if sq.completeSquare(self.playerNum):
241 | self.wonSquares.append(row * 5 + column - 5)
242 | new = True
243 | sq = board.squares[row*5 + column]
244 | if sq.sides[1] == 0:
245 | sq.sides[1] = 1
246 | changed = True
247 | if sq.completeSquare(self.playerNum):
248 | self.wonSquares.append(row * 5 + column)
249 | new = True
250 | if new:
251 | return True
252 | if changed:
253 | return False
254 |
255 | else:
256 | ### Upwards line
257 | if row == 0: pass
258 | else:
259 | if column == 5:
260 | sq = board.squares[row*5 + column - 5 - 1]
261 | if sq.sides[0] == 0:
262 | sq.sides[0] = 1
263 | if sq.completeSquare(self.playerNum):
264 | self.wonSquares.append(row * 5 + column - 5 - 1)
265 | return True
266 | return False
267 | # Drawing a right line at the bottom edge
268 | elif column == 0:
269 | sq = board.squares[row*5 + column - 5]
270 | if sq.sides[2] == 0:
271 | sq.sides[2] = 1
272 | if sq.completeSquare(self.playerNum):
273 | self.wonSquares.append(row * 5 + column - 5)
274 | return True
275 | return False
276 | # Drawing a line in the centre
277 | else:
278 | new = False
279 | changed = False
280 | sq = board.squares[row*5 + column - 5 - 1]
281 | if sq.sides[0] == 0:
282 | sq.sides[0] = 1
283 | changed = True
284 | if sq.completeSquare(self.playerNum):
285 | self.wonSquares.append(row * 5 + column - 5 - 1)
286 | new = True
287 | sq = board.squares[row*5 + column - 5]
288 | if sq.sides[2] == 0:
289 | sq.sides[2] = 1
290 | changed = True
291 | if sq.completeSquare(self.playerNum):
292 | self.wonSquares.append(row * 5 + column - 5)
293 | new = True
294 | if new:
295 | return True
296 | if changed:
297 | return False
298 |
299 | ### Line to the right
300 | # Cant draw a line from right edge
301 | if column == 5: pass
302 | else:
303 | # Drawing a right line at the top edge
304 | if row == 0:
305 | sq = board.squares[row*5 + column]
306 | sq.sides
307 | if sq.sides[1] == 0:
308 | sq.sides[1] = 1
309 | if sq.completeSquare(self.playerNum):
310 | self.wonSquares.append(row * 5 + column)
311 | return True
312 | return False
313 | # Drawing a right line at the bottom edge
314 | elif row == 5:
315 | sq = board.squares[row*5 + column - 5]
316 | if sq.sides[3] == 0:
317 | sq.sides[3] = 1
318 | if sq.completeSquare(self.playerNum):
319 | self.wonSquares.append(row * 5 + column - 5)
320 | return True
321 | return False
322 | # Drawing a line in the centre
323 | else:
324 | new = False
325 | changed = False
326 | sq = board.squares[row*5 + column - 5]
327 | if sq.sides[3] == 0:
328 | sq.sides[3] = 1
329 | changed = True
330 | if sq.completeSquare(self.playerNum):
331 | self.wonSquares.append(row * 5 + column - 5)
332 | new = True
333 | sq = board.squares[row*5 + column]
334 | if sq.sides[1] == 0:
335 | sq.sides[1] = 1
336 | changed = True
337 | if sq.completeSquare(self.playerNum):
338 | self.wonSquares.append(row * 5 + column)
339 | new = True
340 | if new:
341 | return True
342 | if changed:
343 | return False
344 |
345 | # If on the bottom , cannot go bottom
346 | ### Downwards line
347 | if row == 5: pass
348 | else:
349 | if column == 0:
350 | sq = board.squares[row*5 + column]
351 | if sq.sides[2] == 0:
352 | sq.sides[2] = 1
353 | if sq.completeSquare(self.playerNum):
354 | self.wonSquares.append(row * 5 + column)
355 | return True
356 | return False
357 | # Drawing a right line at the bottom edge
358 | elif column == 5:
359 | sq = board.squares[row*5 + column - 1]
360 | if sq.sides[0] == 0:
361 | sq.sides[0] = 1
362 | if sq.completeSquare(self.playerNum):
363 | self.wonSquares.append(row * 5 + column - 1)
364 | return True
365 | return False
366 | # Drawing a line in the centre
367 | else:
368 | new = False
369 | changed = False
370 | sq = board.squares[row*5 + column]
371 | if sq.sides[2] == 0:
372 | sq.sides[2] = 1
373 | changed = True
374 | if sq.completeSquare(self.playerNum):
375 | self.wonSquares.append(row * 5 + column)
376 | new = True
377 | sq = board.squares[row*5 + column - 1]
378 | if sq.sides[0] == 0:
379 | sq.sides[0] = 1
380 | changed = True
381 | if sq.completeSquare(self.playerNum):
382 | self.wonSquares.append(row * 5 + column - 1)
383 | new = True
384 | if new:
385 | return True
386 | if changed:
387 | return False
388 |
389 | # If on the left, cannot go left
390 | ### Left line
391 | if column == 0: pass
392 | else:
393 | if row == 0:
394 | sq = board.squares[row*5 + column - 1]
395 | if sq.sides[1] == 0:
396 | sq.sides[1] = 1
397 | if sq.completeSquare(self.playerNum):
398 | self.wonSquares.append(row * 5 + column - 1)
399 | return True
400 | return False
401 | # Drawing a right line at the bottom edge
402 | elif row == 5:
403 | sq = board.squares[row*5 + column - 5 - 1]
404 | if sq.sides[3] == 0:
405 | sq.sides[3] = 1
406 | if sq.completeSquare(self.playerNum):
407 | self.wonSquares.append(row * 5 + column - 5 - 1)
408 | return True
409 | return False
410 | # Drawing a line in the centre
411 | else:
412 | new = False
413 | changed = False
414 | sq = board.squares[row*5 + column - 1]
415 | if sq.sides[1] == 0:
416 | sq.sides[1] = 1
417 | changed = True
418 | if sq.completeSquare(self.playerNum):
419 | self.wonSquares.append(row * 5 + column - 1)
420 | new = True
421 | sq = board.squares[row*5 + column - 5 - 1]
422 | if sq.sides[3] == 0:
423 | sq.sides[3] = 1
424 | changed = True
425 | if sq.completeSquare(self.playerNum):
426 | self.wonSquares.append(row * 5 + column - 5 - 1)
427 | new = True
428 | if new:
429 | return True
430 | if changed:
431 | return False
432 |
433 |
434 |
435 |
436 | self.position += 1
437 |
438 |
439 | def c():
440 | ans = 0
441 | for p in range(1,37):
442 | for m in range(1,36):
443 | game = Game(p, m, p, m, 60)
444 | game.run()
445 | if game.result():
446 | ans += 1
447 | print(ans)
448 |
449 | if __name__ == '__main__':
450 | NAME = ""
451 | SCHOOL = ""
452 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
453 | p1, m1, p2, m2, t = input().split()
454 | game = Game(int(p1), int(m1), int(p2), int(m2), int(t))
455 | game.run()
456 |
--------------------------------------------------------------------------------
/2017/bio17q3v2.py:
--------------------------------------------------------------------------------
1 | from itertools import product
2 | from collections import defaultdict
3 | import time
4 |
5 | NAME = ""
6 | SCHOOL = ""
7 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
8 | p,i,n,w = (int(x) for x in input().split())
9 |
10 | start = time.time()
11 | """
12 | weights = [x for x in range(1,i+1)]
13 |
14 | for a in range(1,n-p+2):
15 | for x in product(weights, repeat= a):
16 | if sum(x) == w:
17 | combs.add(tuple(sorted(x)))
18 | print(combs)
19 |
20 |
21 | distribution = 0
22 |
23 | for x in product(combs, repeat=p):
24 | if sum(len(y) for y in x) == n:
25 | distribution += 1
26 |
27 | print(distribution)
28 | """
29 |
30 |
31 | def findNum(remainingNum, currentSet=[[]], maximum=100000, wantedLength = 0):
32 | x = []
33 | #print((remainingNum,currentSet))
34 | if remainingNum == 0:
35 | if wantedLength:
36 | if len(currentSet[0]) != wantedLength:
37 | return None
38 | return currentSet
39 | if wantedLength:
40 | if len(currentSet) > wantedLength:
41 | return
42 | for i in range(1,min(maximum + 1,remainingNum + 1)):
43 | y = []
44 | for a in currentSet:
45 | y.append(a + [i])
46 | z = findNum(remainingNum-i, y, maximum, wantedLength)
47 | if wantedLength and z is None:
48 | continue
49 | else:
50 | x += z
51 |
52 |
53 | #print(x)
54 |
55 | return x
56 |
57 | temp = findNum(w, [[]], i)
58 |
59 | combs = []
60 | for x in temp:
61 | if sorted(x) not in combs:
62 | combs.append(x)
63 |
64 | distribution = findNum(n, wantedLength = p)
65 |
66 | print(time.time()-start)
67 |
68 | lengths = defaultdict(int)
69 | for x in combs:
70 | lengths[len(x)] += 1
71 |
72 | total = 0
73 | for x in distribution:
74 | c = 1
75 | for y in x:
76 | c *= lengths[y]
77 | total += c
78 |
79 | print(total)
80 | print(time.time()-start)
81 | #for i in range(p)
82 |
83 |
--------------------------------------------------------------------------------
/2018/bio2018q1.py:
--------------------------------------------------------------------------------
1 | import math
2 |
3 | def calculator(interest, repay):
4 |
5 | amount = 10000
6 | total_repaid = 0
7 |
8 | while amount > 0:
9 | interest_month = math.ceil((interest / 100) * amount)
10 | amount += interest_month
11 | repaid = math.ceil((repay / 100) * amount)
12 | repaid = min(max(5000, repaid), amount)
13 | total_repaid += repaid
14 | amount -= repaid
15 |
16 | print("%.2f" % (total_repaid / 100))
17 |
18 | def b():
19 | print(5)
20 |
21 | def c():
22 | maxPaid = 0
23 | maxI = 0
24 | maxR = 0
25 | for i in range(0,101):
26 | for r in range(0,101):
27 | temp = calculator(i,r)
28 | if temp > maxPaid:
29 | maxPaid = temp
30 | maxI = i
31 | maxR = r
32 | print((maxI, maxR))
33 |
34 | if __name__ == '__main__':
35 | NAME = ""
36 | SCHOOL = ""
37 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
38 | while True:
39 | i, r = (int(x) for x in input().split())
40 | calculator(i,r)
41 |
42 |
--------------------------------------------------------------------------------
/2018/bio2018q2.py:
--------------------------------------------------------------------------------
1 |
2 | def createSecondDial(n):
3 | alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
4 | second_Dial = ""
5 | a = -1
6 | used = ""
7 | for i in range(26):
8 | a += n
9 | a %= 26-i
10 | second_Dial += alphabet[a]
11 | alphabet = alphabet.replace(alphabet[a], "")
12 | a -= 1
13 | return second_Dial
14 |
15 | def encrypt(string, second_Dial):
16 | encrypted = ""
17 | first_Dial = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
18 | for i in range(len(string)):
19 | encrypted += second_Dial[(first_Dial.index(string[i])+i)%26]
20 | return encrypted
21 |
22 | def c():
23 | for i in range(1,1000001):
24 | second_Dial = createSecondDial(i)
25 | x = encrypt("ABCDEFGHIJKLMNOPQRSTUVWXYZ", second_Dial)
26 | if sorted(x) == list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
27 | print(second_Dial)
28 | if __name__ == '__main__':
29 | print("Name: Ryuichi Leo Takashige\nSchool: Westminster School\n")
30 | n, string = input().split()
31 | second_Dial = createSecondDial(int(n))
32 | print(second_Dial[:6])
33 | print(encrypt(string, second_Dial))
34 |
35 |
36 |
37 | """
38 |
39 | def createSecondDial2(n):
40 | alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
41 | second_Dial = ""
42 | a = -1
43 | used = ""
44 | for i in range(26):
45 | for _ in range(n):
46 | a += 1
47 | a%=26
48 | while alphabet[a] in used:
49 | a+=1
50 | a%=26
51 | second_Dial += alphabet[a]
52 | used += alphabet[a]
53 | return second_Dial
54 |
55 | """
56 |
--------------------------------------------------------------------------------
/2018/bio2018q3ownImproved.py:
--------------------------------------------------------------------------------
1 | from functools import lru_cache
2 | from collections import defaultdict
3 | import time
4 |
5 |
6 | @lru_cache(maxsize=None)
7 | def mid(middle, left, right):
8 | return middle < max(left, right) and middle > min(left,right)
9 |
10 |
11 | connections = defaultdict(set)
12 | seen = set()
13 |
14 |
15 | @lru_cache(maxsize=None)
16 | def createEquivalences(string):
17 | seen.add(string)
18 | if len(string) < 3:
19 | connections[string] = set()
20 |
21 | for i in range(len(string)-1):
22 | if i:
23 | if mid(string[i-1], string[i], string[i+1]):
24 | connections[string].add(string[:i]+string[i+1] + string[i] + string[i+2:])
25 | continue
26 | if i!=len(string)-2:
27 | if mid(string[i+2], string[i], string[i+1]):
28 | connections[string].add(string[:i]+string[i+1] + string[i] + string[i+2:])
29 | continue
30 | for x in connections[string]:
31 | if x not in seen:
32 | createEquivalences(x)
33 |
34 |
35 | NAME = ""
36 | SCHOOL = ""
37 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
38 | input()
39 | string = input()
40 | start = time.time()
41 | createEquivalences(string)
42 |
43 |
44 | def bfs(source):
45 | seen = set()
46 | queue = []
47 | depths = defaultdict(int)
48 | queue.append((source,0))
49 | seen.add(source)
50 |
51 | while queue:
52 | x, depth = queue.pop(0)
53 | depths[x] = depth
54 |
55 | for c in connections[x]:
56 | if c not in seen:
57 | queue.append((c,depth+1))
58 | seen.add(x)
59 |
60 | return depths
61 |
62 |
63 | print(max(bfs(string).values()))
64 | print(time.time()-start)
65 |
--------------------------------------------------------------------------------
/2019/bio19q1.py:
--------------------------------------------------------------------------------
1 | def is_palindrome(n):
2 | if n[::-1] == n: return True
3 | else: return False
4 |
5 | def next_palindrome(n):
6 | n+=1
7 | while True:
8 | strn = str(n)
9 | if is_palindrome(strn):
10 | return n
11 | b = True
12 | for i in range(len(strn)//2):
13 | if is_palindrome(strn):
14 | return int(strn)
15 | if b:
16 | if int(strn[i]) >= int(strn[-i-1]):
17 | if i != 0:
18 | temp = strn[:-i-1] + strn[i] + strn[-i:]
19 | else:
20 | temp = strn[:-i-1] + strn[i]
21 | strn = temp
22 | else:
23 | n = int(strn)
24 | x = 10 + int(strn[i]) - int(strn[-i-1])
25 | n += x * 10**i
26 | strn = str(n)
27 | b = False
28 | n = int(strn)
29 |
30 |
31 | def find_all_palindromes(stop):
32 | lst = []
33 | for i in range(0,stop):
34 | if is_palindrome(str(i)):
35 | lst.append(i)
36 | print(len(lst))
37 | ans = []
38 | for i in range(len(lst)):
39 | print(len(ans))
40 | for j in range(i,len(lst)):
41 | k = lst[i]+lst[j]
42 | if k > stop:
43 | break
44 | if k not in ans:
45 | ans.append(k)
46 | print(stop-len(ans))
47 | # Buffers at 90070 so stands to reason that the answer is 9030.
48 |
49 |
50 | if __name__ == '__main__':
51 | NAME = ""
52 | SCHOOL = ""
53 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
54 | while True:
55 | n = input()
56 | print(next_palindrome(int(n)))
57 |
--------------------------------------------------------------------------------
/2019/bio19q2.py:
--------------------------------------------------------------------------------
1 | class Grid():
2 |
3 | def __init__(self, trail_memory):
4 | self.memory = trail_memory
5 | self.trail = []
6 |
7 | def update_grid(self, former_position):
8 | self.trail.append(former_position)
9 | if len(self.trail) > self.memory:
10 | del self.trail[0]
11 |
12 | def valid_move(self, new_position):
13 | if new_position in self.trail:
14 | return False
15 | else:
16 | return True
17 |
18 | class Agent():
19 |
20 | def __init__(self, t, instructions, moves):
21 | self.instructions = instructions * (moves//len(instructions)) + instructions[:moves%len(instructions)]
22 | self.directionList = ["F", "R", "B", "L"]
23 | self.direction = 0
24 | self.position = (0,0)
25 | self.grid = Grid(t)
26 | self.realDirectionDict = [(0,1), (1,0), (0,-1), (-1,0)]
27 |
28 | def explore(self):
29 | for instruction in self.instructions:
30 | moveable = 4
31 | while True:
32 | if moveable == 0:
33 | break
34 | new_direction = self.direction + self.directionList.index(instruction)
35 | new_direction %= 4
36 | new_position = self.change(self.position, self.realDirectionDict[new_direction])
37 | if self.grid.valid_move(new_position):
38 | self.grid.update_grid(self.position)
39 | self.position = new_position
40 | self.direction = new_direction
41 | break
42 | else:
43 | self.direction += 1
44 | self.direction %= 4
45 | moveable -= 1
46 | print(self.position)
47 |
48 | def change(self, pos, move):
49 | return (pos[0] + move[0], pos[1] + move[1])
50 |
51 | def c(self):
52 | pos = []
53 | for x in range(-10,11):
54 | for y in range(-10,11):
55 | pos.append((x,y))
56 |
57 | ans = 0
58 |
59 | while True:
60 | if self.position in pos:
61 | pos.remove(self.position)
62 | if len(pos) == 0:
63 | break
64 |
65 | ans += 1
66 | moveable = 4
67 | while True:
68 | if moveable == 0:
69 | break
70 | new_direction = self.direction + self.directionList.index("L")
71 | new_direction %= 4
72 | new_position = self.change(self.position, self.realDirectionDict[new_direction])
73 | if self.grid.valid_move(new_position):
74 | self.grid.update_grid(self.position)
75 | self.position = new_position
76 | self.direction = new_direction
77 | break
78 | else:
79 | self.direction += 1
80 | self.direction %= 4
81 | moveable -= 1
82 | print(ans)
83 |
84 | def d(self):
85 | for i in range(100):
86 | for instruction in self.instructions:
87 | moveable = 4
88 | while True:
89 | if moveable == 0:
90 | return False
91 | new_direction = self.direction + self.directionList.index(instruction)
92 | new_direction %= 4
93 | new_position = self.change(self.position, self.realDirectionDict[new_direction])
94 | if self.grid.valid_move(new_position):
95 | self.grid.update_grid(self.position)
96 | self.position = new_position
97 | self.direction = new_direction
98 | break
99 | else:
100 | self.direction += 1
101 | self.direction %= 4
102 | moveable -= 1
103 |
104 | return True
105 |
106 |
107 | def c():
108 | agent = Agent(1000000, "L", 1)
109 | agent.c()
110 | # Result 440
111 |
112 | def d():
113 | t = 1300
114 | while True:
115 | agent = Agent(t, "LLRFFF", 6)
116 | if agent.d():
117 | t -= 1
118 | elif t < 100:
119 | print("Fail")
120 | break
121 | else:
122 | print(t)
123 | break
124 |
125 | if __name__ == '__main__':
126 | NAME = ""
127 | SCHOOL = ""
128 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
129 | while True:
130 | print("\n")
131 | t, i, m = input().split()
132 | t, m = int(t), int(m)
133 | agent = Agent(t, i, m)
134 | agent.explore()
135 |
136 |
137 |
--------------------------------------------------------------------------------
/2019/bio19q3.py:
--------------------------------------------------------------------------------
1 | # Uses memoization for speed.
2 | # Did you know that you can't memoize using a list as a key? My solution here was to use * to "unzip" it".
3 |
4 | from functools import lru_cache
5 | import time
6 |
7 | NAME = ""
8 | SCHOOL = ""
9 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
10 | l, p = input().split()
11 | l = int(l)
12 | wanted = l
13 |
14 |
15 | @lru_cache(maxsize=None)
16 | def valid(_tuple):
17 | if _tuple[0] < _tuple[1] and _tuple[2] < _tuple[1]:
18 | return True
19 | if _tuple[0] > _tuple[1]:
20 | return True
21 | return False
22 |
23 |
24 | def valid2(_set):
25 | smallest = _set[0]
26 | for i in range(1, len(_set)):
27 | if _set[i] < smallest:
28 | smallest = _set[i]
29 | else:
30 | for j in range(i+1,len(_set)):
31 | if _set[j] > _set[i]:
32 | return False
33 | return True
34 |
35 | memo = {}
36 |
37 | def count(length, letters, smallest, afterSmallest):
38 | if length==wanted:
39 | return 1
40 | total = 0
41 | for letter in letters:
42 |
43 | _smallest = smallest
44 | _afterSmallest = afterSmallest
45 | if letter < smallest:
46 | _smallest = letter
47 | elif afterSmallest == None:
48 | _afterSmallest = letter
49 | elif letter < afterSmallest:
50 | _afterSmallest = letter
51 | else:
52 | continue
53 |
54 | if length==1:
55 | temp = letters.copy()
56 | temp.remove(letter)
57 | if (length + 1, *temp, _smallest, _afterSmallest) in memo:
58 | total += memo[(length + 1, *temp, _smallest, _afterSmallest)]
59 | else:
60 | x = count(length + 1, temp, _smallest, _afterSmallest)
61 | memo[(length + 1, *temp, _smallest, _afterSmallest)] = x
62 | total += x
63 | continue
64 | # elif valid((string[-2],string[-1],letter)):
65 | temp = letters.copy()
66 | temp.remove(letter)
67 | #if valid2(string + [letter]):
68 | if (length + 1, *temp, _smallest, _afterSmallest) in memo:
69 | total += memo[(length + 1, *temp, _smallest, _afterSmallest)]
70 | else:
71 | x = count(length + 1, temp, _smallest, _afterSmallest)
72 | memo[(length + 1, *temp, _smallest, _afterSmallest)] = x
73 | total += x
74 | return total
75 |
76 | letters = set(x for x in range(l))
77 | used = list(ord(x)-ord("A") for x in p)
78 |
79 | smallest = min(used)
80 | y = used.index(smallest)
81 | afterSmallest = None
82 | if y != len(used) -1:
83 | afterSmallest = 50
84 | for a in range(y,len(used)):
85 | if used[a] < afterSmallest:
86 | afterSmallest = used[a]
87 |
88 | for x in used:
89 | letters.remove(x)
90 | if len(used) > 2:
91 | if valid2(used):
92 | start = time.time()
93 | print(count(len(used), letters, smallest, afterSmallest))
94 | print(time.time()-start)
95 | else:
96 | print(0)
97 | else:
98 | start = time.time()
99 | print(count(len(used), letters, smallest, afterSmallest))
100 | print(time.time()-start)
--------------------------------------------------------------------------------
/2020/bio20q1.py:
--------------------------------------------------------------------------------
1 | """
2 | Q1s are usually not this implementation-heavy, but here we are.
3 | I think you just have to be rigorous for this, and I found it was easiest to split up the look and say functions.
4 | While it is a bit long, each step is very simple, so I haven't commented them.
5 | Please do let me know if you have a shorter solution, though!
6 | """
7 |
8 |
9 | def look(_roman_numeral):
10 | current_letter = None
11 | letters = []
12 | occurrences = []
13 | for x in _roman_numeral:
14 | if x != current_letter:
15 | current_letter = x
16 | letters.append(current_letter)
17 | occurrences.append(1)
18 | else:
19 | occurrences[-1] += 1
20 | return letters, occurrences
21 |
22 |
23 | def roman_numeral(n):
24 | string = ""
25 | thousands = n//1000
26 | string += "M" * thousands
27 | n -= thousands * 1000
28 | if n >= 900:
29 | string += "CM"
30 | n -= 900
31 | if n >= 500:
32 | string += "D"
33 | n -= 500
34 | if n >= 400:
35 | string += "CD"
36 | n -= 400
37 | hundreds = n//100
38 | string += "C" * hundreds
39 | n -= hundreds * 100
40 | if n >= 90:
41 | string += "XC"
42 | n -= 90
43 | if n >= 50:
44 | string += "L"
45 | n -= 50
46 | if n >= 40:
47 | string += "XL"
48 | n -= 40
49 | tens = n//10
50 | string += "X" * tens
51 | n -= tens * 10
52 | if n == 9:
53 | string += "IX"
54 | return string
55 | if n >= 5:
56 | string += "V"
57 | n -= 5
58 | if n == 4:
59 | string += "IV"
60 | return string
61 | units = n
62 | string += "I" * units
63 | return string
64 |
65 |
66 | def say(letters, occurrences):
67 | string = ""
68 | for i in range(len(letters)):
69 | string += roman_numeral(occurrences[i]) + letters[i]
70 | return string
71 |
72 |
73 | def look_and_say(numeral, n):
74 | n = int(n)
75 | for i in range(n):
76 | letters, occurrences = look(numeral)
77 | numeral = say(letters, occurrences)
78 | iCount = 0
79 | vCount = 0
80 | for letter in numeral:
81 | if letter == "I":
82 | iCount += 1
83 | elif letter == "V":
84 | vCount += 1
85 | print(f"{iCount} {vCount}")
86 | return numeral
87 |
88 |
89 | order = ["I", "V", "X", "L", "C", "D", "M"]
90 |
91 |
92 | def valid(roman_numeral):
93 | if "IC" in roman_numeral or "IM" in roman_numeral or "IL" in roman_numeral or "ID" in roman_numeral or roman_numeral == "IIX":
94 | return False
95 | for i in range(len(roman_numeral)-3):
96 | if roman_numeral[i] == roman_numeral[i+1] == roman_numeral[i+2] == roman_numeral[i+3]:
97 | return False
98 | if order.index(roman_numeral[i + 3]) > order.index(roman_numeral[i]):
99 | return False
100 | if roman_numeral[i] == "I" and (roman_numeral[i+1] == "X" or roman_numeral[i+1] == "V") and roman_numeral[i+2] == "I":
101 | return False
102 | if roman_numeral[i] == "I" and roman_numeral[i+1] == "I" and (roman_numeral[i+2] == "V" or roman_numeral[i+2] == "X" or roman_numeral[i+2] == "C" or roman_numeral[i+2] == "M"):
103 | return False
104 | if roman_numeral[i+1] == "I" and (roman_numeral[i+2] == "X" or roman_numeral[i+2] == "V") and roman_numeral[i+3] == "I":
105 | return False
106 | if roman_numeral[i+1] == "I" and roman_numeral[i+2] == "I" and (roman_numeral[i+3] == "V" or roman_numeral[i+3] == "X" or roman_numeral[i+3] == "C" or roman_numeral[i+3] == "M"):
107 | return False
108 | else: return True
109 |
110 |
111 | def b():
112 | for i in range(1,4000):
113 | temp = look_and_say(roman_numeral(i),1)
114 | if valid(temp):
115 | print(temp)
116 |
117 |
118 | def c():
119 | lst = []
120 | for i in range(1,4000):
121 | temp = look_and_say(roman_numeral(i),1)
122 | if temp not in lst:
123 | lst.append(temp)
124 | print(len(lst))
125 |
126 |
127 | if __name__ == '__main__':
128 | NAME = ""
129 | SCHOOL = ""
130 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
131 | while True:
132 | print("\n")
133 | numeral, n = input().split()
134 | look_and_say(numeral, n)
135 |
--------------------------------------------------------------------------------
/2020/bio20q2.py:
--------------------------------------------------------------------------------
1 | alphabet = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
2 |
3 |
4 | class Room():
5 | def __init__(self, roomLetter):
6 | self.Letter = roomLetter
7 | self.connectedRooms = []
8 | self.visited = 0
9 | self.connectionUsed = []
10 |
11 |
12 | class Spy():
13 | def __init__(self, plan, r):
14 | self.plan = plan
15 | self.unexploredRooms = alphabet[:r]
16 | self.nonPlanRooms = []
17 | for room in self.unexploredRooms:
18 | self.nonPlanRooms.append(room)
19 | self.ans = self.rooms = []
20 |
21 | def construct_map(self):
22 | rooms = []
23 | chosen = []
24 | while True:
25 | i = 0
26 | usedRooms = [room.Letter for room in rooms]
27 | if len(self.plan)== 0:
28 | for room in chosen:
29 | self.unexploredRooms.remove(room)
30 | if self.unexploredRooms[0] in usedRooms:
31 | rooms[usedRooms.index(self.unexploredRooms[0])].connectedRooms.append(self.unexploredRooms[1])
32 | else:
33 | rooms.append(Room(self.unexploredRooms[0]))
34 | rooms[-1].connectedRooms.append(self.unexploredRooms[1])
35 | if self.unexploredRooms[1] in usedRooms:
36 | rooms[usedRooms.index(self.unexploredRooms[1])].connectedRooms.append(self.unexploredRooms[0])
37 | else:
38 | rooms.append(Room(self.unexploredRooms[1]))
39 | rooms[-1].connectedRooms.append(self.unexploredRooms[0])
40 | break
41 | while True:
42 | if self.nonPlanRooms[i] not in self.plan:
43 | break
44 | else: i += 1
45 | if self.nonPlanRooms[i] not in usedRooms:
46 | first_room = Room(self.nonPlanRooms[i])
47 | chosen.append(self.nonPlanRooms[i])
48 | first_room.connectedRooms.append(self.plan[0])
49 | rooms.append(first_room)
50 | else:
51 | chosen.append(self.nonPlanRooms[i])
52 | rooms[usedRooms.index(self.nonPlanRooms[i])].connectedRooms.append(self.plan[0])
53 |
54 | if self.plan[0] in usedRooms:
55 | rooms[usedRooms.index(self.plan[0])].connectedRooms.append(self.nonPlanRooms[i])
56 | else:
57 | second_room = Room(self.plan[0])
58 | second_room.connectedRooms.append(self.nonPlanRooms[i])
59 | rooms.append(second_room)
60 | del self.plan[0]
61 | del self.nonPlanRooms[i]
62 | cR = [room.connectedRooms for room in rooms]
63 | rL = [room.Letter for room in rooms]
64 | #####################################################
65 | self.ans = [''.join(s) for s in [sorted(connections) for connections, roomLetters in sorted(zip(cR, rL), key=lambda pair: pair[1])]]
66 | for line in self.ans:
67 | print(line)
68 |
69 | for room in rooms:
70 | room.connectedRooms = sorted(room.connectedRooms)
71 |
72 | self.rooms = [room for room, roomLetter in sorted(zip(rooms, [room.Letter for room in rooms]), key=lambda pair: pair[1])]
73 |
74 | def move(self, n):
75 | for room in self.rooms:
76 | room.visited = 0
77 | room.connectionUsed = []
78 | for i in range(len(room.connectedRooms)):
79 | room.connectionUsed.append(0)
80 | currentLetter = "A"
81 | nextLetter = ""
82 | for moves in range(n):
83 | currentRoom = self.rooms[alphabet.index(currentLetter)]
84 | currentRoom.visited += 1
85 | if currentRoom.visited % 2 == 1:
86 | nextLetter = currentRoom.connectedRooms[0]
87 | currentRoom.connectionUsed[0] += 1
88 | else:
89 | for i in range(len(currentRoom.connectionUsed)):
90 | if currentRoom.connectionUsed[i] % 2 == 1:
91 | if i == len(currentRoom.connectionUsed) -1:
92 | nextLetter = currentRoom.connectedRooms[i]
93 | currentRoom.connectionUsed[i] += 1
94 | else:
95 | nextLetter = currentRoom.connectedRooms[i+1]
96 | currentRoom.connectionUsed[i+1] += 1
97 | break
98 |
99 | currentLetter = nextLetter
100 | return str(currentLetter)
101 |
102 | if __name__ == '__main__':
103 | NAME = ""
104 | SCHOOL = ""
105 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
106 | while True:
107 | print("\n")
108 | plan, p, q = input().split()
109 | spy = Spy(list(plan), len(plan) + 2)
110 | spy.construct_map()
111 | print(spy.move(int(p)) + spy.move(int(q)))
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/2020/bio20q3.py:
--------------------------------------------------------------------------------
1 | # This is HEAVILY inspired by Matthewelse. His solutions are also available on GitHub!
2 |
3 | from functools import lru_cache
4 |
5 |
6 | # The only way that some plans repeat is when they have the same number of characters remaining,
7 | # and the same last character on the prefix.
8 | @lru_cache(maxsize=None)
9 | def count(remaining_characters, last_char, last_char_count, max_char_count, letters):
10 | if last_char_count is not None and last_char_count > max_char_count:
11 | # impossible
12 | return 0
13 | elif remaining_characters == 0:
14 | return 1
15 | else:
16 | total = 0
17 |
18 | for i in range(letters):
19 | if last_char is not None and last_char == i:
20 | total += count(
21 | remaining_characters - 1,
22 | last_char,
23 | last_char_count + 1,
24 | max_char_count,
25 | letters,
26 | )
27 | else:
28 | total += count(remaining_characters - 1, i, 1, max_char_count, letters)
29 |
30 | return total
31 |
32 |
33 | NAME = ""
34 | SCHOOL = ""
35 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
36 |
37 | letters, max_adjacent, expected_length = tuple(int(x) for x in input().split(" "))
38 |
39 | n = int(input())
40 | prefix = []
41 | last = None
42 | last_count = 0
43 |
44 | # Find the nth plan's prefix until the nth plan is constructed.
45 | while len(prefix) < expected_length:
46 | for i in range(letters):
47 | # How many of the past letters (in a row) are the same as this one.
48 | _last_count = last_count + 1 if i == last else 1
49 | prefix.append(i)
50 | with_prefix = count(
51 | expected_length - len(prefix), i, _last_count, max_adjacent, letters
52 | )
53 |
54 | if with_prefix >= n:
55 | # this is the right prefix
56 | last = i
57 | last_count = _last_count
58 | break
59 |
60 | # This wasn't the right prefix.
61 | # So subtract the number of plans starting with this prefix from the number of plans we are searching for.
62 | n -= with_prefix
63 | prefix.pop() # Getting rid of the prefix we temporarily added in this loop.
64 |
65 | # Print the string that is currently stored in an array of ascii numbers.
66 | print("".join(chr(i + ord("A")) for i in prefix))
67 |
--------------------------------------------------------------------------------
/2021/BIO2021q1.py:
--------------------------------------------------------------------------------
1 | from string import ascii_uppercase
2 | from functools import lru_cache
3 | from itertools import permutations
4 |
5 |
6 | # We cache results of the pat() function since we will need to reuse the same strings multiple times.
7 | # We could implement our own memoization, or we can just use lru_cache.
8 | @lru_cache(maxsize=None)
9 | def pat(word):
10 | if len(word) == 1: # A word of length one is definitely a pat.
11 | return True
12 |
13 | # Check all possible splits of the word.
14 | for i in range(len(word) - 1):
15 | left = word[:i + 1]
16 | right = word[i + 1:]
17 |
18 | """
19 | We want to check if every letter in left is smaller (lexicographically) than every letter in right.
20 | For this problem, it is sufficient to do this in O(n^2):
21 | if all(x > y for y in right for x in left)
22 |
23 | However, we can do this in O(n):
24 | We just need to find whether the smallest letter of left is larger than the largest of right!
25 | """
26 |
27 | if min(left) > max(right):
28 | if pat(left[::-1]) and pat(right[::-1]):
29 | return True
30 |
31 | return False
32 |
33 |
34 | def solve():
35 | s1, s2 = input().split()
36 | print("YES" if pat(s1) else "NO")
37 | print("YES" if pat(s2) else "NO")
38 | print("YES" if pat(s1 + s2) else "NO")
39 |
40 |
41 | def b():
42 | p = ["".join(s) for s in permutations("ABCD")]
43 | for string in p:
44 | if pat(string):
45 | print(string)
46 |
47 |
48 | # A modified version of the pat() function.
49 | # Counts the number of pats in a given word.
50 | @lru_cache(maxsize=None)
51 | def num_pats(word):
52 | if len(word) == 1:
53 | return 1
54 |
55 | ans = 0
56 | # Check all possible splits of the word.
57 | for i in range(len(word) - 1):
58 | left = word[:i + 1]
59 | right = word[i + 1:]
60 | if min(left) > max(right):
61 | if pat(left[::-1]) and pat(right[::-1]):
62 | ans += 1
63 |
64 | return ans
65 |
66 |
67 | def c():
68 | # We can check the number of pats up to a couple of letters using num_pats and permutations.
69 | # While you could realise that they are simply the Catalan Numbers,
70 | # let's make a recurrence relation to solve this problem without knowledge of them!
71 | #
72 | # Let P[i] be the number of pats using i+1 letters.
73 | # P[n+1] = Sum of P[i]P[n-i] for all i between 0 and n inclusive.
74 | # (i.e. using the first i letters and then the next n-i letters,
75 | # since the right part must use larger letters than the left.)
76 | #
77 | # We can ignore A because, for any pat starting with B made of letters B...Z,
78 | # there is only one place that the A can go such that the resulting word is also a pat.
79 | # Therefore, we want P[23].
80 |
81 | P = [0 for _ in range(24)]
82 | P[0] = 1
83 | for n in range(23):
84 | for i in range(0, n+1):
85 | P[n+1] += P[i] * P[n-i]
86 |
87 | print(P[23]) # 343059613650
88 |
89 |
90 | if __name__ == '__main__':
91 | NAME = ""
92 | SCHOOL = ""
93 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
94 | solve()
95 |
--------------------------------------------------------------------------------
/2021/BIO2021q2.py:
--------------------------------------------------------------------------------
1 | """
2 | This is an implementation problem, and an extremely finicky one at that!
3 | I recommend really reading the problem carefully and then writing up a high-level plan.
4 | Mine would be:
5 | 1. Get players, moves and respective traversals.
6 | 2. For the number of moves:
7 | 2.1 Traverse a single side.
8 | 2.2 Check if the triangle adjacent to where the player ended up would score the player at least a point.
9 | 2.3 If it will or the player has used up his max. traversals, finish the move, otherwise go back to 2.1.
10 | 2.4 Fill in the triangle adjacent to the player's starting point and check whether it has scored the player a point.
11 | 2.5 Reposition all players if they need to be repositioned.
12 | 3. Print all scores in order.
13 | 4. Traverse from the top-left side until you reach the same side again.
14 | Keep track of the distance travelled to find and print the perimeter.
15 |
16 | One challenge we need to solve is to find a way to store an "infinite" triangular grid.
17 | My way was to use a 2D list as shown below.
18 | [ududu]
19 | [dudud]
20 | [ududu]
21 | where u is a triangle facing upwards and d is facing down.
22 | Since we only have 5000 moves, we don't need a massive 2D array.
23 | """
24 | import numpy as np
25 | from functools import lru_cache
26 | MAXSIZE = 500
27 |
28 | grid = np.zeros(shape=(MAXSIZE*2+1, MAXSIZE*2+1))
29 |
30 | grid[MAXSIZE][MAXSIZE] = -1
31 |
32 | """ 1
33 | / \ \-----/
34 | 1 / \ 2 3 \ / 2 Side numbers
35 | /_____\ \ /
36 | 3
37 | """
38 |
39 |
40 | # Check the three 'larger triangles' around the cell at a certain row and column
41 | def score(row, column, player_num):
42 | def match(r, c):
43 | return grid[r][c] == player_num
44 | # Notice that in odd index rows, odd columns are facing up and on even rows, even columns are facing up.
45 | if row%2==column%2: # Facing up
46 | return int(match(row-1, column+1) and match(row, column+2)) + \
47 | int(match(row-1, column-1) and match(row, column-2)) + \
48 | int(match(row+1, column-1) and match(row+1, column+1))
49 |
50 | else: # Facing down
51 | return int(match(row+1, column-1) and match(row, column-2)) + \
52 | int(match(row+1, column+1) and match(row, column+2)) + \
53 | int(match(row-1, column-1) and match(row-1, column+1))
54 |
55 |
56 | # dRow, dColumn, new side
57 | up = {
58 | 1: [
59 | (-1, -1, 3),
60 | (-1, 0, 3),
61 | (-1, 1, 1),
62 | (0, 1, 1),
63 | (0, 0, 2)
64 | ],
65 |
66 | 2: [
67 | (0, 2, 1),
68 | (1, 2, 1),
69 | (1, 1, 2),
70 | (1, 0, 2),
71 | (0, 0, 3)
72 | ],
73 |
74 | 3: [
75 | (1, -1, 2),
76 | (1, -2, 2),
77 | (0, -2, 3),
78 | (0, -1, 3),
79 | (0, 0, 1)
80 | ]
81 | }
82 |
83 | # We check almost exactly the same triangles as above.
84 | # So we can copy some bits from above, but this is still q2. It is going to be a bit tedious!
85 | down = {
86 | 1: [
87 | (-1, 1, 3),
88 | (-1, 2, 1),
89 | (0, 2, 1),
90 | (0, 1, 2),
91 | (0, 0, 2)
92 | ],
93 |
94 | 2: [
95 | (1, 1, 1),
96 | (1, 0, 2),
97 | (1, -1, 2),
98 | (0, -1, 3),
99 | (0, 0, 3)
100 | ],
101 |
102 | 3: [
103 | (0, -2, 2),
104 | (-1, -2, 3),
105 | (-1, -1, 3),
106 | (-1, 0, 1),
107 | (0, 0, 1)
108 | ]
109 | }
110 |
111 |
112 | between_up = {
113 | 1: (0, -1),
114 | 2: (0, 1),
115 | 3: (1, 0)
116 | }
117 |
118 | between_down = {
119 | 1: (-1, 0),
120 | 2: (0, 1),
121 | 3: (0, -1)
122 | }
123 |
124 | # Store the top left triangle and starting point globally.
125 | topleft = (500, 500)
126 | topside = 1
127 |
128 |
129 | @lru_cache(maxsize=None)
130 | def adjacent(row, column, side):
131 | if row%2 == column%2:
132 | dRow, dCol = between_up[side]
133 | else:
134 | dRow, dCol = between_down[side]
135 | return row + dRow, column + dCol
136 |
137 |
138 | class Player:
139 | def __init__(self, num, traversals_per_move):
140 | self.row = self.column = MAXSIZE
141 | self.side = 1
142 | self.num = num
143 | self.traversals = traversals_per_move
144 | self.points = 0
145 |
146 | def traverse(self):
147 | for i in range(5):
148 | if self.row % 2 == self.column % 2:
149 | dRow, dColumn, new = up[self.side][i]
150 | else:
151 | dRow, dColumn, new = down[self.side][i]
152 |
153 | if grid[self.row + dRow][self.column + dColumn]:
154 | self.row += dRow
155 | self.column += dColumn
156 | self.side = new
157 | break
158 |
159 | def move(self):
160 | global topleft, topside
161 | # Debugging is especially essential for q2.
162 | # print(f"Player {self.num}")
163 | # Store the position of the triangle adjacent to the player.
164 | start_row, start_col = adjacent(self.row, self.column, self.side)
165 |
166 | for i in range(self.traversals):
167 | self.traverse()
168 | temp_row, temp_col = adjacent(self.row, self.column, self.side)
169 | if score(temp_row, temp_col, self.num):
170 | break
171 |
172 | # Fill in the start point, and check whether that new triangle is the top left one.
173 | grid[start_row][start_col] = self.num
174 | if start_row < topleft[0] or start_row == topleft[0] and start_col < topleft[1]:
175 | topleft = (start_row, start_col)
176 | topside = 1 if start_row%2==start_col%2 else 3
177 |
178 | # Check if the player gets any points this turn.
179 | self.points += score(start_row, start_col, self.num)
180 | # print(self.row, self.column, self.side)
181 | # print("\n".join(str(x[496:505]).replace(" ", "") for x in grid[496:505]))
182 | # print("\n")
183 |
184 | def reposition(self):
185 | adjRow, adjCol = adjacent(self.row, self.column, self.side)
186 |
187 | if grid[adjRow][adjCol]:
188 | self.row, self.column = topleft
189 | self.side = topside
190 |
191 |
192 | def find_perimeter():
193 | temp = Player(-1, 0)
194 | temp.row, temp.column = topleft
195 | temp.side = topside
196 | perimeter = 0
197 | while True:
198 | temp.traverse()
199 | perimeter += 1
200 | if (temp.row, temp.column) == topleft and temp.side == topside:
201 | print(perimeter)
202 | break
203 |
204 |
205 | def solve():
206 | p, moves = (int(x) for x in input().split())
207 | players = []
208 | traversals = [int(x) for x in input().split()]
209 | for i in range(p):
210 | players.append(Player(i+1, traversals[i]))
211 |
212 | while moves != 0:
213 | for i in range(p):
214 | players[i].move()
215 | for j in range(p):
216 | players[j].reposition()
217 | moves -= 1
218 | if moves == 0:
219 | break
220 |
221 | for i in range(p):
222 | print(players[i].points)
223 |
224 | find_perimeter()
225 |
226 |
227 | def b():
228 | # Just do this by hand! Free marks :)
229 | return
230 |
231 |
232 | def c():
233 | global grid, topleft, topside, MAXSIZE
234 | MAXSIZE = 6
235 |
236 | def reset():
237 | global grid, topleft, topside
238 | grid = np.zeros(shape=(MAXSIZE * 2 + 1, MAXSIZE * 2 + 1))
239 |
240 | grid[MAXSIZE][MAXSIZE] = -1
241 | topleft = (MAXSIZE, MAXSIZE)
242 | topside = 1
243 | m = 4
244 | wanted = np.zeros(shape=(MAXSIZE * 2 + 1, MAXSIZE * 2 + 1))
245 | wanted[MAXSIZE][MAXSIZE] = -1
246 | wanted[MAXSIZE][MAXSIZE-2] = 1
247 | wanted[MAXSIZE][MAXSIZE-1] = 1
248 | wanted[MAXSIZE+1][MAXSIZE-2] = 1
249 | wanted[MAXSIZE+1][MAXSIZE] = 1
250 |
251 | # Realistically, we only need to check between 1 and 100 (the scope of the original problem)
252 | for i in range(1, 101):
253 | reset()
254 | player = Player(1, i)
255 | for _ in range(m):
256 | player.move()
257 | player.reposition()
258 |
259 | # See if the grid we created is the exact same as the grid we wanted.
260 | finished = True
261 | for j in range(MAXSIZE*2+1):
262 | for k in range(MAXSIZE*2+1):
263 | if grid[j][k] != wanted[j][k]:
264 | finished = False
265 | if finished:
266 | print(i) # 51
267 |
268 |
269 | def d():
270 | # Solve with 2 5000\n 5 7 to fill the grid initially.
271 | unfilled = 0
272 | seen = set()
273 | from collections import deque
274 | queue = deque()
275 |
276 | # Fill in the triangles outside the perimeter.
277 | def fill(row, column):
278 | queue.append((row, column))
279 |
280 | while queue:
281 | r, c = queue.popleft()
282 | grid[r][c] = -1
283 | up = r%2==c%2
284 | if r:
285 | if not up and (r-1, c) not in seen and not grid[r-1, c]:
286 | seen.add((r-1, c))
287 | queue.append((r-1, c))
288 | if c:
289 | if (r, c-1) not in seen and not grid[r, c-1]:
290 | seen.add((r, c-1))
291 | queue.append((r, c-1))
292 | if r < 1000:
293 | if up and (r+1, c) not in seen and not grid[r+1, c]:
294 | seen.add((r+1, c))
295 | queue.append((r+1, c))
296 | if c < 1000:
297 | if (r, c+1) not in seen and not grid[r, c+1]:
298 | seen.add((r, c+1))
299 | queue.append((r, c+1))
300 |
301 | fill(0, 0)
302 | # Find the triangles still not filled.
303 | for i in range(1001):
304 | for j in range(1001):
305 | if not grid[i][j]:
306 | unfilled += 1
307 | print(unfilled) # 377
308 |
309 |
310 | if __name__ == '__main__':
311 | NAME = ""
312 | SCHOOL = ""
313 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
314 | solve()
315 | # c()
316 | # d()
317 |
--------------------------------------------------------------------------------
/2021/BIO2021q3.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 | from itertools import permutations
3 | warehouse = ["A", "B", "C", "D", "E", "F", "G", "H"]
4 |
5 |
6 | # Implement the three operations in the question.
7 | def add(cur):
8 | cur += warehouse[len(cur)]
9 | return cur
10 |
11 |
12 | def swap(cur):
13 | return cur[:2][::-1] + cur[2:]
14 |
15 |
16 | def rotate(cur):
17 | return cur[1:] + cur[0]
18 |
19 |
20 | def bfs(start, target):
21 | steps = {start: 0} # Stores number of steps required to get to a state.
22 | queue = deque()
23 | queue.append(start)
24 | target_len = len(target)
25 | cur = ""
26 | res = None
27 |
28 | def on_reached(state):
29 | # We only care if the new value hasn't been reached.
30 | # If it has been reached earlier, it was reached in the same or fewer steps.
31 | if state not in steps:
32 | steps[state] = steps[cur] + 1
33 | if state == target:
34 | return steps[state]
35 | queue.append(state)
36 |
37 | while queue:
38 | cur = queue.popleft()
39 | len_cur = len(cur)
40 |
41 | if len_cur < target_len: # If there are boxes left at the warehouse
42 | new = add(cur)
43 | # Call the on_reached() function and return the result if it exists.
44 | res = on_reached(new)
45 | if res:
46 | return res
47 |
48 | if len_cur > 1: # If at least two boxes
49 | new = swap(cur)
50 | res = on_reached(new)
51 | if res:
52 | return res
53 |
54 | if len_cur: # If at least one box
55 | new = rotate(cur)
56 | res = on_reached(new)
57 | if res:
58 | return res
59 |
60 |
61 | def solve():
62 | global warehouse
63 | target = input()
64 | start = ""
65 | warehouse = warehouse[:len(target)]
66 | print(bfs(start, target)) # Find the minimum steps to get from the start state to the target state.
67 |
68 |
69 | def b():
70 | global warehouse
71 | p = ["".join(s) for s in permutations("ABCDE")]
72 | warehouse = warehouse[:5]
73 |
74 | for string in p:
75 | min_ops = bfs("", string)
76 | if min_ops == 6:
77 | print(string)
78 |
79 |
80 | def modified_bfs(start, target, length):
81 | # Instead of storing the minimum steps to reach a state,
82 | # let's store the ways to make a state in a certain number of steps.
83 | # e.g. we can make the starting value in 0 steps in exactly 1 way!
84 | ways = {(start, 0): 1}
85 | queue = deque()
86 | queue.append((start, 0))
87 | target_len = len(target)
88 |
89 | while queue:
90 | cur, steps = queue.popleft()
91 |
92 | if steps == length:
93 | print(ways[(target, length)]) # 84
94 | exit(0)
95 |
96 | len_cur = len(cur)
97 |
98 | if len_cur < target_len:
99 | new = add(cur)
100 | if (new, steps+1) not in ways:
101 | ways[(new, steps+1)] = ways[(cur, steps)]
102 | queue.append((new, steps+1))
103 |
104 | else:
105 | ways[(new, steps+1)] += ways[(cur, steps)]
106 |
107 | if len_cur > 1: # If at least two boxes
108 | new = swap(cur)
109 | if (new, steps + 1) not in ways:
110 | ways[(new, steps + 1)] = ways[(cur, steps)]
111 | queue.append((new, steps + 1))
112 |
113 | else:
114 | ways[(new, steps + 1)] += ways[(cur, steps)]
115 |
116 | if len_cur: # If at least one box
117 | new = rotate(cur)
118 | if (new, steps + 1) not in ways:
119 | ways[(new, steps + 1)] = ways[(cur, steps)]
120 | queue.append((new, steps + 1))
121 |
122 | else:
123 | ways[(new, steps + 1)] += ways[(cur, steps)]
124 |
125 |
126 | def c():
127 | modified_bfs("", "HGFEDCBA", 24)
128 |
129 |
130 | if __name__ == '__main__':
131 | NAME = ""
132 | SCHOOL = ""
133 | print(f"Name: {NAME}\nSchool: {SCHOOL}")
134 | solve()
135 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # British-Informatics-Olympiad
2 |
3 |
4 | Very readable, relatively easy-to-understand solutions for the British Informatics Olympiad.
5 | While most of these solutions are done without any help, a few of these files are modified versions of code by **Matthewelse** and **Spookiel**. I definitely recommend checking them out.
6 |
7 | Please don't hesitate to send any improvements, though I will only make these changes as long as the code remains readable.
8 |
9 | Disclaimer: These are by no means official solutions and are written solely in Python. Not all solutions are complete or give full marks, but the most recent years should be more complete.
10 |
11 | These things said, I hope these are helpful to programmers practicing for this and similar competitions.
12 |
13 | **Tips:**
14 |
15 | 1. (Optional) Get Pycharm! I used to use the standard IDLE, but Pycharm has helped me improve my efficiency significantly, especially for longer pieces of code.
16 | 2. Learn the basics - Python syntax (or you might use another language), recursion, BFS, DFS and memoization are all pretty much essential for the BIO. The BIO doesn't really stretch far beyond these concepts, though. If you want more diverse problems, I recommend CSES and Codeforces. If you want more maths, go for Project Euler!
17 | 3. Try the problems first on your own, whether it takes 10 minutes, an hour or 3 hours! The problems from earlier years are definitely easier, so perhaps start with those.
18 | 4. Once you have, find how you scored. Did you end up with a logical error? Or did you get a TLE? Or was it perfect?
19 | 5. Whatever your outcome, check these solutions; the comments and the variable names should help you get a better understanding of the problem.
20 | 6. When testing, being able to input multiple test cases is often handy. I don't recommend going as far as unit testing, but try using a while loop.
21 | 7. Then leave it for a while and try doing the problem on your own again!
22 | 8. I sometimes add comments in the extra description, so do check them out. (You can access this when you are looking at a solution by pressing the ... next to the description at the top).
23 |
24 |
--------------------------------------------------------------------------------
/docs/googled40a215ed9e79ad6.html:
--------------------------------------------------------------------------------
1 | google-site-verification: googled40a215ed9e79ad6.html
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | British Informatics Olympiad Solutions (in Python)
4 |
5 |
6 |
7 |
8 |
9 | British Informatics Olympiad Solutions (in Python)
10 |
11 |
12 |
13 |
14 | Visit My Github page!
15 |
16 | Very readable, relatively easy-to-understand solutions for the British Informatics Olympiad.
17 | Please do check it out!
18 |
19 |
20 |
--------------------------------------------------------------------------------