├── Qualification Round ├── second_hands.py3 ├── second_meaning.py3 ├── second_friend.py3 ├── second_second_meaning.py3 ├── second_flight2.py3 ├── second_flight.py3 └── second_second_friend.py3 ├── Round 1 ├── consecutive_cuts_chapter_1.py3 ├── watering_well_chapter_2.py3 ├── watering_well_chapter_1.py3 ├── consecutive_cuts_chapter_2-2.py3 ├── consecutive_cuts_chapter_2-3.py3 ├── consecutive_cuts_chapter_2.py3 └── lemonade_life.py3 ├── LICENSE ├── Round 3 ├── third_trie.py3 ├── fourth_player.py3 ├── first_time_chapter_1.py3 ├── second_mistake.py3 ├── first_time_chapter_2.py3 ├── zero_crossings_chapter_1_2.py3 ├── zero_crossings_chapter_1.py3 └── zero_crossings_chapter_2.py3 ├── Round 2 ├── perfectly_balanced_chapter_1.py3 ├── balance_sheet.py3 ├── balance_scale.py3 ├── perfectly_balanced_chapter_2.py3 ├── work_life_balance_chapter_1.py3 └── work_life_balance_chapter_2.py3 ├── Final Round ├── emerald_exhibiting.py3 ├── ml_modeling.py3 ├── tile_transposing2.py3 ├── cup_counterbalancing.py3 ├── hazelnut_harvesting.py3 ├── tile_transposing.py3 └── alphabet_adventuring.py3 └── README.md /Qualification Round/second_hands.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Qualification Round - Problem A. Second Hands 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/A 5 | # 6 | # Time: O(N) 7 | # Space: O(N) 8 | # 9 | 10 | from collections import Counter 11 | 12 | def second_hands(): 13 | N, K = map(int, input().split()) 14 | S = map(int, input().split()) 15 | return "YES" if N <= 2*K and max(Counter(S).values()) <= 2 else "NO" 16 | 17 | for case in range(int(input())): 18 | print('Case #%d: %s' % (case+1, second_hands())) 19 | -------------------------------------------------------------------------------- /Qualification Round/second_meaning.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Qualification Round - Problem C1. Second Meaning 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/C1 5 | # 6 | # Time: O(N^2) 7 | # Space: O(N) 8 | # 9 | 10 | def encode(n, x): 11 | code = ['-' if x == '.' else '.', x] 12 | result = [code[0]]*(n+1) 13 | result.append(code[1]) 14 | return "".join(result) 15 | 16 | def second_meaning(): 17 | N = int(input()) 18 | S = input() 19 | result = [encode(i, S[0]) for i in range(N-1)] 20 | return "\n%s" % "\n".join(result) 21 | 22 | for case in range(int(input())): 23 | print('Case #%d: %s' % (case+1, second_meaning())) 24 | -------------------------------------------------------------------------------- /Qualification Round/second_friend.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Qualification Round - Problem B1. Second Friend 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/B1 5 | # 6 | # Time: O(R * C) 7 | # Space: O(1) 8 | # 9 | 10 | def second_friend(): 11 | R, C = map(int, input().split()) 12 | grid = [list(input()) for _ in range(R)] 13 | if min(R, C) == 1 and any(x == '^' for row in grid for x in row): 14 | return "Impossible" 15 | x = '.' if min(R, C) == 1 else '^' 16 | for r in range(len(grid)): 17 | for c in range(len(grid[0])): 18 | grid[r][c] = x 19 | return "Possible\n%s" % "\n".join(map(lambda x: "".join(x), grid)) 20 | 21 | for case in range(int(input())): 22 | print('Case #%d: %s' % (case+1, second_friend())) 23 | -------------------------------------------------------------------------------- /Round 1/consecutive_cuts_chapter_1.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 1 - Problem A1. Consecutive Cuts - Chapter 1 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/A1 5 | # 6 | # Time: O(N) 7 | # Space: O(1) 8 | # 9 | 10 | def check(A, B, i): 11 | return all(A[(i+j)%len(A)] == B[j]for j in range(len(A))) 12 | 13 | def consecutive_cuts_chapter_1(): 14 | N, K = map(int, input().split()) 15 | A = list(map(int, input().split())) 16 | B = list(map(int, input().split())) 17 | i = A.index(B[0]) 18 | if check(A, B, i): 19 | if (N == 2 and K%2 == int(i != 0)) or (N > 2 and K != int(i == 0)): 20 | return "YES" 21 | return "NO" 22 | 23 | for case in range(int(input())): 24 | print('Case #%d: %s' % (case+1, consecutive_cuts_chapter_1())) 25 | -------------------------------------------------------------------------------- /Qualification Round/second_second_meaning.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Qualification Round - Problem C2. Second Second Meaning 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/C2 5 | # 6 | # Time: O(NlogN) 7 | # Space: O(logN) 8 | # 9 | 10 | def encode(n, x, l): 11 | code = ['-' if x == '.' else '.', x] 12 | result = [] 13 | for i in reversed(range(l)): 14 | result.append(code[(n>>i)&1]) 15 | return "".join(result) 16 | 17 | def second_second_meaning(): 18 | N = int(input()) 19 | S = input() 20 | ceil_log2_N = (N-1).bit_length() 21 | result = [encode(i, S[0], ceil_log2_N+1) for i in range(N-1)] 22 | return "\n%s" % "\n".join(result) 23 | 24 | for case in range(int(input())): 25 | print('Case #%d: %s' % (case+1, second_second_meaning())) 26 | -------------------------------------------------------------------------------- /Round 1/watering_well_chapter_2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 1 - Problem B2. Watering Well - Chapter 2 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/B2 5 | # 6 | # Time: O(N + Q) 7 | # Space: O(1) 8 | # 9 | 10 | def watering_well_chapter_2(): 11 | N = int(input()) 12 | A_square_total = A_total = B_square_total = B_total = 0 13 | for _ in range(N): 14 | A, B = list(map(int, input().split())) 15 | A_total, A_square_total = (A_total+A)%MOD, (A_square_total+A**2)%MOD 16 | B_total, B_square_total = (B_total+B)%MOD, (B_square_total+B**2)%MOD 17 | result = 0 18 | for _ in range(int(input())): 19 | X, Y = list(map(int, input().split())) 20 | result = (result+(N*X**2-2*A_total*X+A_square_total))%MOD 21 | result = (result+(N*Y**2-2*B_total*Y+B_square_total))%MOD 22 | return result 23 | 24 | MOD = 10**9+7 25 | for case in range(int(input())): 26 | print('Case #%d: %s' % (case+1, watering_well_chapter_2())) 27 | -------------------------------------------------------------------------------- /Round 1/watering_well_chapter_1.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 1 - Problem B1. Watering Well - Chapter 1 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/B1 5 | # 6 | # Time: O(N + Q + min(N * Q, MAX_A_B_X_Y^2)) 7 | # Space: O(min(N + Q, MAX_A_B_X_Y)) 8 | # 9 | 10 | from collections import Counter 11 | 12 | def count(n): 13 | X_cnt, Y_cnt = Counter(), Counter() 14 | for _ in range(n): 15 | X, Y = list(map(int, input().split())) 16 | X_cnt[X] += 1 17 | Y_cnt[Y] += 1 18 | return X_cnt, Y_cnt 19 | 20 | def f(X_cnt, A_cnt): 21 | result = 0 22 | for X, cntX in X_cnt.items(): 23 | for A, cntA in A_cnt.items(): 24 | result = (result+cntX*cntA*(X-A)**2)%MOD 25 | return result 26 | 27 | def watering_well_chapter_1(): 28 | A_cnt, B_cnt = count(int(input())) 29 | X_cnt, Y_cnt = count(int(input())) 30 | return (f(X_cnt, A_cnt)+f(Y_cnt, B_cnt))%MOD 31 | 32 | MOD = 10**9+7 33 | for case in range(int(input())): 34 | print('Case #%d: %s' % (case+1, watering_well_chapter_1())) 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 kamyu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Round 3/third_trie.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 3 - Problem B. Third Trie 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/B 5 | # 6 | # Time: O(N * M) 7 | # Space: O(T), T is the size of the merged trie 8 | # 9 | 10 | def nC3(n): 11 | return n*(n-1)*(n-2)//6 12 | 13 | def third_trie(): 14 | def create_node(): 15 | trie.append([0]*26) 16 | cnt.append(0) 17 | return len(trie)-1 18 | 19 | N = int(input()) 20 | trie = [[0]*26] 21 | cnt = [0] 22 | for _ in range(N): 23 | M = int(input()) 24 | lookup = [0] 25 | cnt[lookup[-1]] += 1 26 | for _ in range(M-1): 27 | P, C = input().split() 28 | P = int(P) 29 | if not trie[lookup[P-1]][ord(C)-ord('a')]: 30 | trie[lookup[P-1]][ord(C)-ord('a')] = create_node() 31 | lookup.append(trie[lookup[P-1]][ord(C)-ord('a')]) 32 | cnt[lookup[-1]] += 1 33 | return sum(nC3(N)-nC3(N-c) for c in cnt) 34 | 35 | for case in range(int(input())): 36 | print('Case #%d: %s' % (case+1, third_trie())) 37 | -------------------------------------------------------------------------------- /Round 3/fourth_player.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 3 - Problem A. Fourth Player 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/A 5 | # 6 | # Time: O(NlogN) 7 | # Space: O(N) 8 | # 9 | 10 | def fourth_player(): 11 | N = int(input()) 12 | A, B = [], [] 13 | for i in range(4): 14 | C = list(map(int, input().split())) 15 | C.sort() 16 | if i == 0: 17 | new_A, new_B = C, [] 18 | else: 19 | new_A, new_B = [], [] 20 | for x in reversed(B): 21 | if C and C[-1] > x: 22 | new_A.append(C.pop()) 23 | else: 24 | new_B.append(x) 25 | for x in A: 26 | if C and C[-1] > x: 27 | new_A.append(C.pop()) 28 | else: 29 | new_A.append(x) 30 | new_A.sort() 31 | new_B.reverse() # the same as new_B.sort() 32 | B, A = new_A, new_B 33 | return len(A) 34 | 35 | for case in range(int(input())): 36 | print('Case #%d: %s' % (case+1, fourth_player())) 37 | -------------------------------------------------------------------------------- /Round 3/first_time_chapter_1.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 3 - Problem D1. First Time - Chapter 1 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/D1 5 | # 6 | # Time: O(M + NlogN) 7 | # Space: O(N) 8 | # 9 | 10 | def ceil_divide(a, b): 11 | return (a+b-1)//b 12 | 13 | def first_time_chapter_1(): 14 | def merge(a, b): # Total Time: O(NlogN) 15 | if len(group[a]) > len(group[b]): 16 | group[a], group[b] = group[b], group[a] 17 | cnt = len(group[a])+len(group[b]) 18 | while group[a]: 19 | group[b].add(group[a].pop()) 20 | return cnt-len(group[b]) 21 | 22 | N, M, K = map(int, input().split()) 23 | group = [{i//K} for i in range(N)] 24 | result = INF 25 | cnt = N-ceil_divide(N, K) 26 | for t in range(1, M+1): 27 | A, B = map(int, input().split()) 28 | cnt -= merge(A-1, B-1) 29 | if cnt == 0: 30 | result = min(result, t) 31 | return result if result != INF else -1 32 | 33 | INF = float("inf") 34 | for case in range(int(input())): 35 | print('Case #%d: %s' % (case+1, first_time_chapter_1())) 36 | -------------------------------------------------------------------------------- /Qualification Round/second_flight2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Qualification Round - Problem D. Second Flight 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/D 5 | # 6 | # Time: O(N + Q + M * min(sqrt(Q), N)) 7 | # Space: O(N + M + Q) 8 | # 9 | 10 | def second_flight(): 11 | N, M, Q = map(int, input().split()) 12 | adj = [{} for _ in range(N)] 13 | for _ in range(M): 14 | A, B, C = map(int, input().split()) 15 | A -= 1 16 | B -= 1 17 | adj[A][B] = adj[B][A] = C 18 | result = [] 19 | lookup = {} 20 | for _ in range(Q): 21 | X, Y = map(int, input().split()) 22 | X -= 1 23 | Y -= 1 24 | if (len(adj[X]), X) > (len(adj[Y]), Y): 25 | X, Y = Y, X 26 | if (X, Y) not in lookup: 27 | cnt = sum(min(adj[X][Z], adj[Y][Z]) for Z in adj[X].keys() if Z in adj[Y]) 28 | if Y in adj[X]: 29 | cnt += 2*adj[X][Y] 30 | lookup[X, Y] = cnt 31 | result.append(lookup[X, Y]) 32 | return " ".join(map(str, result)) 33 | 34 | for case in range(int(input())): 35 | print('Case #%d: %s' % (case+1, second_flight())) 36 | -------------------------------------------------------------------------------- /Round 1/consecutive_cuts_chapter_2-2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 1 - Problem A2. Consecutive Cuts - Chapter 2 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/A2 5 | # 6 | # Time: O(N) 7 | # Space: O(N) 8 | # 9 | # z-function solution 10 | # 11 | 12 | # Template: https://cp-algorithms.com/string/z-function.html 13 | def z_function(s): # Time: O(n), Space: O(n) 14 | z = [0]*len(s) 15 | l, r = 0, 0 16 | for i in range(1, len(z)): 17 | if i <= r: 18 | z[i] = min(r-i+1, z[i-l]) 19 | while i+z[i] < len(z) and s[z[i]] == s[i+z[i]]: 20 | z[i] += 1 21 | if i+z[i]-1 > r: 22 | l, r = i, i+z[i]-1 23 | return z 24 | 25 | def consecutive_cuts_chapter_2(): 26 | N, K = map(int, input().split()) 27 | A = list(map(int, input().split())) 28 | B = list(map(int, input().split())) 29 | z = z_function(B+A+A) 30 | for i in range(N): 31 | if z[i+N] < N: 32 | continue 33 | if (N == 2 and K%2 == int(i != 0)) or (N > 2 and K != int(i == 0)): 34 | return "YES" 35 | return "NO" 36 | 37 | for case in range(int(input())): 38 | print('Case #%d: %s' % (case+1, consecutive_cuts_chapter_2())) 39 | -------------------------------------------------------------------------------- /Round 1/consecutive_cuts_chapter_2-3.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 1 - Problem A2. Consecutive Cuts - Chapter 2 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/A2 5 | # 6 | # Time: O(N) 7 | # Space: O(1) 8 | # 9 | # rolling hash solution 10 | # 11 | 12 | from functools import reduce 13 | 14 | def check(A, B, i): 15 | return all(A[(i+j)%len(A)] == B[j]for j in range(len(A))) 16 | 17 | def hash(nums): 18 | return [reduce(lambda h, x: (h*p+x)%MOD, nums) for p in P] 19 | 20 | def update(h, base, x): 21 | return [(h[i]*P[i]+x*(1-base[i]))%MOD for i in range(len(P))] 22 | 23 | def consecutive_cuts_chapter_2(): 24 | N, K = map(int, input().split()) 25 | A = list(map(int, input().split())) 26 | B = list(map(int, input().split())) 27 | base = [pow(p, N, MOD) for p in P] 28 | got, want = hash(A), hash(B) 29 | for i in range(N): 30 | if got == want and check(A, B, i): 31 | if (N == 2 and K%2 == int(i != 0)) or (N > 2 and K != int(i == 0)): 32 | return "YES" 33 | got = update(got, base, A[i]) 34 | return "NO" 35 | 36 | MOD, P = 10**9+7, (113, 109) # double hash (single hash is enough) 37 | for case in range(int(input())): 38 | print('Case #%d: %s' % (case+1, consecutive_cuts_chapter_2())) 39 | -------------------------------------------------------------------------------- /Round 2/perfectly_balanced_chapter_1.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 2 - Problem A1. Perfectly Balanced - Chapter 1 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/A1 5 | # 6 | # Time: O(N + Q) 7 | # Space: O(N) 8 | # 9 | 10 | def perfectly_balanced_chapter_1(): 11 | S = input() 12 | prefix = [[0]*26] 13 | for c in S: 14 | prefix.append(prefix[-1][:]) 15 | prefix[-1][ord(c)-ord('a')] += 1 16 | result = 0 17 | for _ in range(int(input())): 18 | L, R = map(int, input().split()) 19 | L -= 1 20 | R -= 1 21 | if (R-L+1)%2 == 0: 22 | continue 23 | cnt1 = [prefix[(L+R)//2+1][i]-prefix[L][i] for i in range(26)] 24 | cnt2 = [prefix[R+1][i]-prefix[(L+R)//2+1][i] for i in range(26)] 25 | if sum(abs(cnt1[i]-cnt2[i]) for i in range(26)) == 1: 26 | result += 1 27 | continue 28 | cnt1 = [prefix[(L+R)//2][i]-prefix[L][i] for i in range(26)] 29 | cnt2 = [prefix[R+1][i]-prefix[(L+R)//2][i] for i in range(26)] 30 | if sum(abs(cnt2[i]-cnt1[i]) for i in range(26)) == 1: 31 | result += 1 32 | continue 33 | return result 34 | 35 | for case in range(int(input())): 36 | print('Case #%d: %s' % (case+1, perfectly_balanced_chapter_1())) 37 | -------------------------------------------------------------------------------- /Round 1/consecutive_cuts_chapter_2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 1 - Problem A2. Consecutive Cuts - Chapter 2 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/A2 5 | # 6 | # Time: O(N) 7 | # Space: O(N) 8 | # 9 | # kmp solution 10 | # 11 | 12 | def getPrefix(pattern): 13 | prefix = [-1]*len(pattern) 14 | j = -1 15 | for i in range(1, len(pattern)): 16 | while j+1 > 0 and pattern[j+1] != pattern[i]: 17 | j = prefix[j] 18 | if pattern[j+1] == pattern[i]: 19 | j += 1 20 | prefix[i] = j 21 | return prefix 22 | 23 | def KMP(text, pattern, start): 24 | prefix = getPrefix(pattern) 25 | j = -1 26 | for i in range(start, len(text)): 27 | while j+1 > 0 and pattern[j+1] != text[i]: 28 | j = prefix[j] 29 | if pattern[j+1] == text[i]: 30 | j += 1 31 | if j+1 == len(pattern): 32 | yield i-j 33 | j = prefix[j] 34 | 35 | def consecutive_cuts_chapter_2(): 36 | N, K = map(int, input().split()) 37 | A = list(map(int, input().split())) 38 | B = list(map(int, input().split())) 39 | for i in KMP(A+A, B, 0): 40 | if i >= N: 41 | break 42 | if (N == 2 and K%2 == int(i != 0)) or (N > 2 and K != int(i == 0)): 43 | return "YES" 44 | return "NO" 45 | 46 | for case in range(int(input())): 47 | print('Case #%d: %s' % (case+1, consecutive_cuts_chapter_2())) 48 | -------------------------------------------------------------------------------- /Round 2/balance_sheet.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 2 - Problem B. Balance Sheet 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/B 5 | # 6 | # Time: O(NlogN + N * K) 7 | # Space: O(N * K) 8 | # 9 | 10 | from functools import reduce 11 | 12 | def balance_sheet(): 13 | def merge(a, b): 14 | result = [] 15 | i = j = 0 16 | while (i < len(a) or j < len(b)) and len(result) < K: 17 | if j == len(b) or (i < len(a) and a[i] > b[j]): 18 | result.append(a[i]) 19 | i += 1 20 | else: 21 | result.append(b[j]) 22 | j += 1 23 | return result 24 | 25 | N, K = map(int, input().split()) 26 | events = [] 27 | for i in range(N): 28 | A, B, X, Y = map(int, input().split()) 29 | events.append((A, X, 'B', i)) 30 | events.append((B, Y, 'S', i)) 31 | events.sort(reverse=True) 32 | dp = [[0] for _ in range(N)] 33 | buy = [] 34 | for idx, (d, p, t, i) in enumerate(events): 35 | if t == 'B': 36 | buy = merge(buy, [x+p for x in dp[i]]) 37 | else: 38 | dp[i] = merge(dp[i], [x-p for x in buy]) 39 | if idx+1 < len(events) and events[idx+1][0] != d: 40 | buy.clear() 41 | return reduce((lambda x, y: (x+y)%MOD), reduce(merge, dp), 0) 42 | 43 | MOD = 10**9+7 44 | for case in range(int(input())): 45 | print('Case #%d: %s' % (case+1, balance_sheet())) 46 | -------------------------------------------------------------------------------- /Round 3/second_mistake.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 3 - Problem C. Second Mistake 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/C 5 | # 6 | # Time: O(3 * L * (N + Q)) 7 | # Space: O(3 * L * N) 8 | # 9 | 10 | from collections import Counter 11 | from functools import reduce 12 | 13 | def add(a, b): 14 | return (a+b)%MOD 15 | 16 | def mult(a, b): 17 | return (a*b)%MOD 18 | 19 | def pow(i): 20 | while not (i < len(POW)): 21 | POW.append(mult(POW[-1], BASE)) 22 | return POW[i] 23 | 24 | def second_mistake(): 25 | def find_diff_1_hashes(f): 26 | result = 0 27 | for _ in range(int(input())): 28 | V = input() 29 | h = reduce(lambda h, i: add(h, mult(LOOKUP[V[i]], pow(i))), range(len(V)), 0) 30 | result += sum(f(add(h, mult(LOOKUP[x]-LOOKUP[c], pow(i))), i) for i, c in enumerate(V) for x in LOOKUP.keys() if x != c) 31 | return result//2 32 | 33 | def f(h, i): 34 | cnt[h, i] += 1 35 | cnt[h] += 1 36 | return 0 37 | 38 | def g(h, i): 39 | return (cnt[h] if h in cnt else 0)-(cnt[h, i] if (h, i) in cnt else 0) 40 | 41 | cnt = Counter() 42 | return find_diff_1_hashes(f)+find_diff_1_hashes(g) 43 | 44 | MOD = (1<<64)-59 # largest 64-bit prime 45 | BASE = 113 46 | POW = [1] 47 | META = "meta" 48 | LOOKUP = {x:i for i, x in enumerate(META)} 49 | for case in range(int(input())): 50 | print('Case #%d: %s' % (case+1, second_mistake())) 51 | -------------------------------------------------------------------------------- /Round 2/balance_scale.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 2 - Problem C. Balance Scale 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/C 5 | # 6 | # Time: precompute: O(MAX_N * MAX_C) 7 | # runtime: O(N) 8 | # Space: precompute: O(MAX_N * MAX_C) 9 | # runtime: O(1) 10 | # 11 | 12 | def add(a, b): 13 | return (a+b)%MOD 14 | 15 | def sub(a, b): 16 | return (a-b)%MOD 17 | 18 | def mult(a, b): 19 | return (a*b)%MOD 20 | 21 | def lazy_init(n): 22 | while len(INV) <= n: 23 | FACT.append(FACT[-1]*len(INV) % MOD) 24 | INV.append(INV[MOD%len(INV)]*(MOD-MOD//len(INV)) % MOD) 25 | INV_FACT.append(INV_FACT[-1]*INV[-1] % MOD) 26 | 27 | def nCr(n, k, inverse=False): 28 | if not (0 <= k <= n): 29 | return 0 30 | lazy_init(n) 31 | return (FACT[n]*INV_FACT[n-k] % MOD) * INV_FACT[k] % MOD if not inverse else (INV_FACT[n]*FACT[n-k] % MOD) * FACT[k] % MOD 32 | 33 | def inv(n): 34 | lazy_init(n) 35 | return INV[n] 36 | 37 | def balance_scale(): 38 | N, K = map(int, input().split()) 39 | C_W = [tuple(map(int, input().split())) for _ in range(N)] 40 | less = sum(c for c, w in C_W if w < C_W[0][1]) 41 | equal = sum(c for c, w in C_W if w == C_W[0][1]) 42 | total = sum(c for c, _ in C_W) 43 | return mult(mult(sub(nCr(less+equal, K+1), nCr(less, K+1)), mult(C_W[0][0], inv(equal))), nCr(total, K+1, True)) 44 | 45 | FACT, INV, INV_FACT = [[1]*2 for _ in range(3)] 46 | MOD = 10**9+7 47 | for case in range(int(input())): 48 | print('Case #%d: %s' % (case+1, balance_scale())) 49 | -------------------------------------------------------------------------------- /Qualification Round/second_flight.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Qualification Round - Problem D. Second Flight 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/D 5 | # 6 | # Time: O(N + (M + Q) * sqrt(M)) 7 | # Space: O(N + M * sqrt(M)) 8 | # 9 | 10 | from collections import Counter 11 | 12 | def second_flight(): 13 | N, M, Q = map(int, input().split()) 14 | adj = [{} for _ in range(N)] 15 | for _ in range(M): 16 | A, B, C = map(int, input().split()) 17 | A -= 1 18 | B -= 1 19 | adj[A][B] = adj[B][A] = C 20 | count = [Counter() for _ in range(N)] 21 | for Y in range(N): # Time: O(M * sqrt(M)), Space: O(M * sqrt(M)) 22 | if len(adj[Y]) <= M**0.5: 23 | continue 24 | for Z in adj[Y].keys(): 25 | for X in adj[Z].keys(): 26 | if X == Y or (len(adj[X]), X) > (len(adj[Y]), Y): 27 | continue 28 | count[X][Y] += min(adj[X][Z], adj[Y][Z]) 29 | result = [] 30 | for _ in range(Q): # Time: O(Q * sqrt(M)) 31 | X, Y = map(int, input().split()) 32 | X -= 1 33 | Y -= 1 34 | if (len(adj[X]), X) > (len(adj[Y]), Y): 35 | X, Y = Y, X 36 | cnt = count[X][Y] if len(adj[Y]) > M**0.5 else sum(min(adj[X][Z], adj[Y][Z]) for Z in adj[X].keys() if Z in adj[Y]) 37 | if Y in adj[X]: 38 | cnt += 2*adj[X][Y] 39 | result.append(cnt) 40 | return " ".join(map(str, result)) 41 | 42 | for case in range(int(input())): 43 | print('Case #%d: %s' % (case+1, second_flight())) 44 | -------------------------------------------------------------------------------- /Final Round/emerald_exhibiting.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Final Round - Problem B. Emerald Exhibiting 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/B 5 | # 6 | # Time: O(P * logN), pass in PyPy3 but Python3 7 | # Space: O(MAX_N) 8 | # 9 | 10 | def linear_sieve_of_eratosthenes(n): 11 | primes = [] 12 | spf = [-1]*(n+1) # the smallest prime factor 13 | for i in range(2, n+1): 14 | if spf[i] == -1: 15 | spf[i] = i 16 | primes.append(i) 17 | for p in primes: 18 | if i*p > n or p > spf[i]: 19 | break 20 | spf[i*p] = p 21 | return primes 22 | 23 | def count(n, p): 24 | result = 0 25 | while n//p: 26 | result += n//p 27 | n //= p 28 | return result 29 | 30 | def emerald_exhibiting(): 31 | N, K = map(int, input().split()) 32 | if N == K: 33 | return 1 34 | is_one = is_two = is_three = True 35 | is_two_even_cnt = False 36 | total = 1 37 | for p in PRIMES: 38 | if p > N-1: 39 | break 40 | k = count(N-1, p)-count(K, p) 41 | if k%2: 42 | is_one = False 43 | if p%4 == 3 and k%2: # reference: https://en.wikipedia.org/wiki/Sum_of_two_squares_theorem 44 | is_two = False 45 | if p == 2: 46 | if not k%2: 47 | is_two_even_cnt = True 48 | elif k%2: 49 | total = total*p%8 50 | if is_two_even_cnt and total == 7: # (N-1)!/K! = 4^a(8b+7), reference: https://en.wikipedia.org/wiki/Legendre%27s_three-square_theorem 51 | is_three = False 52 | return 1 if is_one else 2 if is_two else 3 if is_three else 4 # reference: https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem 53 | 54 | MAX_N = 10**9 55 | PRIMES = linear_sieve_of_eratosthenes(MAX_N-1) 56 | for case in range(int(input())): 57 | print('Case #%d: %s' % (case+1, emerald_exhibiting())) 58 | -------------------------------------------------------------------------------- /Final Round/ml_modeling.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Final Round - Problem A. ML Modeling 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/A 5 | # 6 | # Time: O(MAX_X * MAX_Y * MAX_R * MIN_N + (MAX_X * MAX_Y)^2 + N), pass in PyPy3 but Python3 7 | # Space: O(MAX_X * MAX_Y) 8 | # 9 | 10 | from math import atan2 11 | 12 | def check(P, x, y, r): 13 | return all((P[i][0]-x)**2 + (P[i][1]-y)**2 <= r**2 for i in range(MIN_N)) 14 | 15 | def overlapped_area(ax, ay, bx, by, r): 16 | d = ((ax-bx)**2+(ay-by)**2)**0.5 17 | h = (r**2-(d/2)**2)**0.5 18 | return 2*(r**2 * atan2(h, d/2))-h*d 19 | 20 | def total_distance_square(P, x, y): 21 | return sum((p[0]-x)**2+(p[1]-y)**2 for p in P) 22 | 23 | def ml_modeling(): 24 | N = int(input()) 25 | P = [list(map(float, input().split())) for _ in range(N)] 26 | candidates = [] 27 | for x in range(MIN_X, MAX_X+1): 28 | for y in range(MIN_Y, MAX_Y+1): 29 | for r in range(MIN_R, MAX_R+1): 30 | if check(P, x, y, r): 31 | candidates.append((x, y, r)) 32 | break 33 | mn = (float("inf"), -1, -1, -1, -1, -1) 34 | for i in range(len(candidates)): 35 | ax, ay, ar = candidates[i] 36 | for j in range(i+1, len(candidates)): 37 | bx, by, br = candidates[j] 38 | if br != ar: 39 | continue 40 | r = ar 41 | if (ax-bx)**2+(ay-by)**2 >= (2*r)**2: 42 | continue 43 | mn = min(mn, (overlapped_area(ax, ay, bx, by, r), ax, ay, bx, by, r)) 44 | _, ax, ay, bx, by, r = mn 45 | if total_distance_square(P, ax, ay) > total_distance_square(P, bx, by): 46 | ax, ay, bx, by = bx, by, ax, ay 47 | return f"{ax} {ay} {bx} {by} {r}" 48 | 49 | MIN_N = 500 50 | MIN_X = MIN_Y = 0 51 | MIN_R = 1 52 | MAX_X = MAX_Y = MAX_R = 50 53 | for case in range(int(input())): 54 | print('Case #%d: %s' % (case+1, ml_modeling())) 55 | -------------------------------------------------------------------------------- /Qualification Round/second_second_friend.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Qualification Round - Problem B1. Second Second Friend 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/B2 5 | # 6 | # Time: O(R * C) 7 | # Space: O(R * C) 8 | # 9 | 10 | def count(grid, r, c): 11 | cnt = 0 12 | for dr, dc in DIRECTIONS: 13 | nr, nc = r+dr, c+dc 14 | if not (0 <= nr < len(grid) and 0 <= nc < len(grid[0]) and grid[nr][nc] != '#'): 15 | continue 16 | cnt += 1 17 | return cnt 18 | 19 | def second_second_friend(): 20 | R, C = map(int, input().split()) 21 | grid = [list(input()) for _ in range(R)] 22 | lookup = [[False]*len(grid[0]) for _ in range(len(grid))] 23 | cnt = [[0]*len(grid[0]) for _ in range(len(grid))] 24 | q = [] 25 | for r in range(len(grid)): 26 | for c in range(len(grid[0])): 27 | if grid[r][c] == '#': 28 | continue 29 | if grid[r][c] == '^': 30 | lookup[r][c] = True 31 | else: 32 | grid[r][c] = '^' 33 | cnt[r][c] = count(grid, r, c) 34 | if cnt[r][c] > 1: 35 | continue 36 | cnt[r][c] = 0 37 | q.append((r, c)) 38 | while q: 39 | new_q = [] 40 | for r, c in q: 41 | if lookup[r][c]: 42 | return "Impossible" 43 | grid[r][c] = '.' 44 | for dr, dc in DIRECTIONS: 45 | nr, nc = r+dr, c+dc 46 | if not (0 <= nr < len(grid) and 0 <= nc < len(grid[0]) and cnt[nr][nc]): 47 | continue 48 | cnt[nr][nc] -= 1 49 | if cnt[nr][nc] > 1: 50 | continue 51 | cnt[nr][nc] = 0 52 | new_q.append((nr, nc)) 53 | q = new_q 54 | return "Possible\n%s" % "\n".join(map(lambda x: "".join(x), grid)) 55 | 56 | DIRECTIONS = ((0, 1), (1, 0), (0, -1), (-1, 0)) 57 | for case in range(int(input())): 58 | print('Case #%d: %s' % (case+1, second_second_friend())) 59 | -------------------------------------------------------------------------------- /Round 1/lemonade_life.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 1 - Problem C. Lemonade Life 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/C 5 | # 6 | # Time: O(NlogN + V^2), O(V) = O(len(hull)) = O(MAX_X_Y^(2/3)), pass in PyPy3 but Python3 7 | # Space: O(N + V) 8 | # 9 | 10 | # Template: https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#Python 11 | def convex_hull(points): # Time: O(NlogN), Space: O(N) 12 | points = sorted(set(points)) 13 | 14 | if len(points) <= 1: 15 | return points 16 | 17 | def cross(o, a, b): 18 | return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) 19 | 20 | lower = [] 21 | for p in points: 22 | while len(lower) >= 2 and cross(lower[-2], lower[-1], p) <= 0: 23 | lower.pop() 24 | lower.append(p) 25 | upper = [] 26 | for p in reversed(points): 27 | while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0: 28 | upper.pop() 29 | upper.append(p) 30 | return lower[:-1] + upper[:-1] 31 | 32 | def lemonade_life(): 33 | N, K, D = map(int, input().split()) 34 | houses = [tuple(map(int, input().split())) for _ in range(N)] 35 | hull = convex_hull(houses) 36 | src, dst = hull.index(houses[0]), hull.index(houses[-1]) 37 | dist = [INF]*len(hull) 38 | dist[src] = 0 39 | lookup = [False]*len(hull) 40 | for _ in range(len(hull)): # Time: O(V^2), Space: O(V) 41 | u = dst 42 | for v in range(len(hull)): 43 | if lookup[v]: 44 | continue 45 | if dist[v] < dist[u]: 46 | u = v 47 | if u == dst: 48 | break 49 | lookup[u] = True 50 | for v in range(len(hull)): 51 | if lookup[v]: 52 | continue 53 | d = (hull[u][0]-hull[v][0])**2+(hull[u][1]-hull[v][1])**2 54 | if d <= D**2: 55 | dist[v] = min(dist[v], dist[u]+max(K, d)) 56 | return dist[dst] if dist[dst] != INF else -1 57 | 58 | INF = float("inf") 59 | for case in range(int(input())): 60 | print('Case #%d: %s' % (case+1, lemonade_life())) 61 | -------------------------------------------------------------------------------- /Round 2/perfectly_balanced_chapter_2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 2 - Problem A2. Perfectly Balanced - Chapter 2 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/A2 5 | # 6 | # Time: O((N + Q) * logN) 7 | # Space: O(N) 8 | # 9 | 10 | from random import seed, randint 11 | 12 | def add(a, b): 13 | return (a+b)%MOD 14 | 15 | def sub(a, b): 16 | return (a-b)%MOD 17 | 18 | class BIT(object): # 0-indexed. 19 | def __init__(self, n): 20 | self.__bit = [0]*(n+1) # Extra one for dummy node. 21 | 22 | def add(self, i, val): 23 | i += 1 # Extra one for dummy node. 24 | while i < len(self.__bit): 25 | self.__bit[i] = add(self.__bit[i], val) # modified 26 | i += (i & -i) 27 | 28 | def query(self, i): 29 | i += 1 # Extra one for dummy node. 30 | ret = 0 31 | while i > 0: 32 | ret = add(ret, self.__bit[i]) # modified 33 | i -= (i & -i) 34 | return ret 35 | 36 | def hash(lookup, h_set, x): 37 | if x not in lookup: 38 | lookup[x] = randint(0, MOD-1) 39 | h_set.add(lookup[x]) 40 | return lookup[x] 41 | 42 | def perfectly_balanced_chapter_2(): 43 | N = int(input()) 44 | A = list(map(int, input().split())) 45 | lookup, h_set = {}, set() 46 | bit = BIT(len(A)) 47 | for i, x in enumerate(A): 48 | bit.add(i, hash(lookup, h_set, x)) 49 | result = 0 50 | for _ in range(int(input())): 51 | args = list(map(int, input().split())) 52 | if args[0] == 1: 53 | _, X, Y = args 54 | X -= 1 55 | bit.add(X, -hash(lookup, h_set, A[X])) 56 | A[X] = Y 57 | bit.add(X, hash(lookup, h_set, A[X])) 58 | continue 59 | _, L, R = args 60 | L -= 1 61 | R -= 1 62 | if (R-L+1)%2 == 0: 63 | continue 64 | h1 = sub(bit.query((L+R)//2), bit.query(L-1)) 65 | h2 = sub(bit.query(R), bit.query((L+R)//2)) 66 | if sub(h1, h2) in h_set: 67 | result += 1 68 | continue 69 | h1 = sub(bit.query((L+R)//2-1), bit.query(L-1)) 70 | h2 = sub(bit.query(R), bit.query((L+R)//2-1)) 71 | if sub(h2, h1) in h_set: 72 | result += 1 73 | continue 74 | return result 75 | 76 | seed(0) 77 | MOD = 1<<64 78 | for case in range(int(input())): 79 | print('Case #%d: %s' % (case+1, perfectly_balanced_chapter_2())) 80 | -------------------------------------------------------------------------------- /Round 2/work_life_balance_chapter_1.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 2 - Problem D1. Work-Life Balance - Chapter 1 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/D1 5 | # 6 | # Time: O((N + M) * logN) 7 | # Space: O(N) 8 | # 9 | 10 | class BIT(object): # 0-indexed. 11 | def __init__(self, n): 12 | self.__bit = [0]*(n+1) # Extra one for dummy node. 13 | 14 | def add(self, i, val): 15 | i += 1 # Extra one for dummy node. 16 | while i < len(self.__bit): 17 | self.__bit[i] += val 18 | i += (i & -i) 19 | 20 | def query(self, i): 21 | i += 1 # Extra one for dummy node. 22 | ret = 0 23 | while i > 0: 24 | ret += self.__bit[i] 25 | i -= (i & -i) 26 | return ret 27 | 28 | def swap(left, right, x, y, cnt): 29 | left[x] -= cnt 30 | right[x] += cnt 31 | right[y] -= cnt 32 | left[y] += cnt 33 | 34 | def update(total, diff, left, right, x, y): 35 | cnt = min(left[x], right[y], diff//(y-x)) 36 | swap(left, right, x, y, cnt) 37 | diff -= cnt*(y-x) 38 | total += cnt 39 | return total, diff 40 | 41 | def work_life_balance_chapter_1(): 42 | def query(Z): 43 | left = [bits[i].query(Z) for i in range(3)] 44 | right = [bits[i].query(N-1)-left[i] for i in range(3)] 45 | diff = sum((i+1)*right[i] for i in range(3))-sum((i+1)*left[i] for i in range(3)) 46 | if diff == 0: 47 | return 0 48 | if diff%2: 49 | return -1 50 | diff //= 2 51 | if diff < 0: 52 | diff = -diff 53 | left, right = right, left 54 | total, diff = update(0, diff, left, right, 0, 2) 55 | total, diff = update(total, diff, left, right, 0, 1) 56 | total, diff = update(total, diff, left, right, 1, 2) 57 | return total if diff == 0 else -1 58 | 59 | N, M = map(int, input().split()) 60 | A = list(map(lambda x: int(x)-1, input().split())) 61 | bits = [BIT(N) for _ in range(3)] 62 | for i, x in enumerate(A): 63 | bits[x].add(i, 1) 64 | result = 0 65 | for _ in range(M): 66 | X, Y, Z = map(lambda x: int(x)-1, input().split()) 67 | bits[A[X]].add(X, -1) 68 | A[X] = Y 69 | bits[A[X]].add(X, 1) 70 | result += query(Z) 71 | return result 72 | 73 | INF = float("inf") 74 | for case in range(int(input())): 75 | print('Case #%d: %s' % (case+1, work_life_balance_chapter_1())) 76 | -------------------------------------------------------------------------------- /Round 3/first_time_chapter_2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 3 - Problem D2. First Time - Chapter 2 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/D2 5 | # 6 | # Time: O(M + NlogN) 7 | # Space: O(N) 8 | # 9 | 10 | def gcd(a, b): 11 | while b: 12 | a, b = b, a%b 13 | return a 14 | 15 | # Template: 16 | # https://github.com/kamyu104/LeetCode-Solutions/blob/master/Python/longest-increasing-subsequence-ii.py 17 | class SegmentTree(object): 18 | def __init__(self, N, 19 | build_fn=lambda _: 0, 20 | query_fn=lambda x, y: y if x is None else x if y is None else max(x, y), 21 | update_fn=lambda x: x): 22 | self.tree = [None]*(2*2**((N-1).bit_length())) 23 | self.base = len(self.tree)//2 24 | self.query_fn = query_fn 25 | self.update_fn = update_fn 26 | for i in range(self.base, self.base+N): 27 | self.tree[i] = build_fn(i-self.base) 28 | for i in reversed(range(1, self.base)): 29 | self.tree[i] = query_fn(self.tree[2*i], self.tree[2*i+1]) 30 | 31 | def update(self, i, h): 32 | x = self.base+i 33 | self.tree[x] = self.update_fn(h) 34 | while x > 1: 35 | x //= 2 36 | self.tree[x] = self.query_fn(self.tree[x*2], self.tree[x*2+1]) 37 | 38 | def first_time_chapter_2(): 39 | def merge(a, b): # Total Time: O(NlogN) 40 | if len(group[a]) > len(group[b]): 41 | group[a], group[b] = group[b], group[a] 42 | for x in group[a]: # only keep the start of the segment with the same color 43 | if x-1 in group[b]: 44 | st.update(x, 0) 45 | if x+1 in group[b]: 46 | st.update(x+1, 0) 47 | while group[a]: 48 | group[b].add(group[a].pop()) 49 | 50 | N, M = map(int, input().split()) 51 | group = [{i} for i in range(N)] 52 | st = SegmentTree(N, 53 | build_fn=lambda i: i, 54 | query_fn=lambda x, y: y if x is None else x if y is None else gcd(x, y)) 55 | result = [INF]*(N+1) 56 | result[1] = 0 57 | for t in range(1, M+1): 58 | A, B = map(int, input().split()) 59 | merge(A-1, B-1) 60 | g = st.tree[1] # gcd of all the starts of the segments with the same color 61 | result[g] = min(result[g], t) 62 | for K in range(1, N+1): # Time: O(NlogN) 63 | result[K] = min(result[nK] for nK in range(0, N+1, K)) 64 | return sum(result[K] if result[K] != INF else -1 for K in range(1, N+1)) 65 | 66 | INF = float("inf") 67 | for case in range(int(input())): 68 | print('Case #%d: %s' % (case+1, first_time_chapter_2())) 69 | -------------------------------------------------------------------------------- /Round 2/work_life_balance_chapter_2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 2 - Problem D2. Work-Life Balance - Chapter 2 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/D2 5 | # 6 | # Time: O((N + M) * logN) 7 | # Space: O(N) 8 | # 9 | 10 | # Template: 11 | # https://github.com/kamyu104/FacebookHackerCup-2021/blob/main/Round%203/expl_ore_ation_chapter_3-2.py 12 | class BIT(object): # 0-indexed. 13 | def __init__(self, n): 14 | self.__bit = [0]*(n+1) # Extra one for dummy node. 15 | 16 | def add(self, i, val): 17 | i += 1 # Extra one for dummy node. 18 | while i < len(self.__bit): 19 | self.__bit[i] += val 20 | i += (i & -i) 21 | 22 | def query(self, i): 23 | i += 1 # Extra one for dummy node. 24 | ret = 0 25 | while i > 0: 26 | ret += self.__bit[i] 27 | i -= (i & -i) 28 | return ret 29 | 30 | def kth_element(self, k): 31 | floor_log2_n = (len(self.__bit)-1).bit_length()-1 32 | pow_i = 2**floor_log2_n 33 | total = pos = 0 # 1-indexed 34 | for _ in reversed(range(floor_log2_n+1)): # O(logN) 35 | if pos+pow_i < len(self.__bit) and total+self.__bit[pos+pow_i] < k: # find max pos s.t. total < k 36 | total += self.__bit[pos+pow_i] 37 | pos += pow_i 38 | pow_i >>= 1 39 | return (pos+1)-1 # 0-indexed, return min pos s.t. total >= k if pos exists else n 40 | 41 | def work_life_balance_chapter_2(): 42 | def query(Z): 43 | left = [bits[i].query(Z) for i in range(2)] 44 | right = [bits[i].query(N-1)-left[i] for i in range(2)] 45 | diff = sum((i+1)*right[i] for i in range(2))-sum((i+1)*left[i] for i in range(2)) 46 | if diff == 0: 47 | return 0 48 | if diff%2: 49 | return -1 50 | diff //= 2 51 | x, y = 0, 1 52 | if diff < 0: 53 | diff = -diff 54 | x, y = y, x 55 | if left[x] < diff or right[y] < diff: 56 | return -1 57 | l = bits[x].kth_element(left[x]-diff) 58 | r = bits[y].kth_element(left[y]+diff) 59 | return (bits2[y].query(r)-bits2[y].query(Z))-(bits2[x].query(Z)-bits2[x].query(l)) 60 | 61 | N, M = map(int, input().split()) 62 | A = list(map(lambda x: int(x)-1, input().split())) 63 | bits = [BIT(N) for _ in range(2)] 64 | bits2 = [BIT(N) for _ in range(2)] 65 | for i, x in enumerate(A): 66 | bits[x].add(i, 1) 67 | bits2[x].add(i, i) 68 | result = 0 69 | for _ in range(M): 70 | X, Y, Z = map(lambda x: int(x)-1, input().split()) 71 | bits[A[X]].add(X, -1) 72 | bits2[A[X]].add(X, -X) 73 | A[X] = Y 74 | bits[A[X]].add(X, 1) 75 | bits2[A[X]].add(X, X) 76 | result += query(Z) 77 | return result 78 | 79 | INF = float("inf") 80 | for case in range(int(input())): 81 | print('Case #%d: %s' % (case+1, work_life_balance_chapter_2())) 82 | -------------------------------------------------------------------------------- /Final Round/tile_transposing2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Final Round - Problem C. Tile Transposing 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/C 5 | # 6 | # Time: O(M * N * log(M * N)^2), pass in PyPy3 but Python3 7 | # Space: O(M * N) 8 | # 9 | # faster but worse time complexity 10 | # 11 | 12 | class PersistentUnionFind(object): # Time: O(n * logn), Space: O(n) 13 | def __init__(self, n): 14 | self.set = list(range(n)) 15 | self.size = [1]*n 16 | self.snapshots = [] # added 17 | self.undos = [] # added 18 | 19 | def find_set(self, x): 20 | while self.set[x] != x: # no path compression 21 | x = self.set[x] 22 | return x 23 | 24 | def union_set(self, x, y): 25 | x, y = self.find_set(x), self.find_set(y) 26 | if x == y: 27 | return False 28 | if self.size[x] > self.size[y]: # union by size 29 | x, y = y, x 30 | self.undos.append((x, y)) # added 31 | self.set[x] = self.set[y] 32 | self.size[y] += self.size[x] 33 | return True 34 | 35 | def total(self, x): 36 | return self.size[self.find_set(x)] 37 | 38 | def snapshot(self): # added 39 | self.snapshots.append(len(self.undos)) 40 | 41 | def rollback(self): # added 42 | for _ in range(len(self.undos)-self.snapshots.pop()): 43 | x, y = self.undos.pop() 44 | self.size[y] -= self.size[x] 45 | self.set[x] = x 46 | 47 | def tile_transposing(): 48 | def merge(i): 49 | r, c = divmod(i, C) 50 | for dr, dc in DIRECTIONS: 51 | nr, nc = r+dr, c+dc 52 | ni = nr*C+nc 53 | if 0 <= nr < R and 0 <= nc < C and G[ni] == G[i] and lookup[ni]: 54 | uf.union_set(i, ni) 55 | 56 | def clear(i): 57 | r, c = divmod(i, C) 58 | for dr, dc in DIRECTIONS: 59 | nr, nc = r+dr, c+dc 60 | ni = nr*C+nc 61 | if not (0 <= nr < R and 0 <= nc < C and G[ni] != G[i]): 62 | continue 63 | uf.snapshot() 64 | for dr, dc in DIRECTIONS: 65 | nnr, nnc = nr+dr, nc+dc 66 | nni = nnr*C+nnc 67 | if 0 <= nnr < R and 0 <= nnc < C and nni != i and G[nni] == G[i]: 68 | uf.union_set(i, nni) 69 | if uf.total(i) >= 3: 70 | result[0] += uf.total(i) 71 | uf.rollback() 72 | 73 | def dfs(left, right): 74 | if left == right: 75 | clear(left) 76 | return 77 | mid = left + (right-left)//2 78 | l1, r1, l2, r2 = left, mid, mid+1, right 79 | for _ in range(2): 80 | uf.snapshot() 81 | for i in range(l1, r1+1): 82 | lookup[i] = True 83 | merge(i) 84 | dfs(l2, r2) 85 | for i in range(l1, r1+1): 86 | lookup[i] = False 87 | uf.rollback() 88 | l1, r1, l2, r2 = l2, r2, l1, r1 89 | 90 | R, C = map(int, input().split()) 91 | G = [] 92 | for _ in range(R): 93 | G.extend(map(int, input().split())) 94 | uf = PersistentUnionFind(R*C) 95 | lookup = [False]*(R*C) 96 | result = [0] 97 | dfs(0, len(lookup)-1) 98 | return result[0]*2 99 | 100 | DIRECTIONS = ((1, 0), (0, 1), (-1, 0), (0, -1)) 101 | for case in range(int(input())): 102 | print('Case #%d: %s' % (case+1, tile_transposing())) 103 | -------------------------------------------------------------------------------- /Final Round/cup_counterbalancing.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Final Round - Problem F. Cup Counterbalancing 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/F 5 | # 6 | # Time: O(N * S), pass in PyPy3 but Python3 7 | # Space: O(N) 8 | # 9 | 10 | from random import random, seed 11 | from math import atan2, pi, cos, sin 12 | 13 | def inner_product(a, b): 14 | return a[0]*b[0]+a[1]*b[1] 15 | 16 | def add(a, b): 17 | return [a[0]+b[0], a[1]+b[1]] 18 | 19 | def sub(a, b): 20 | return [a[0]-b[0], a[1]-b[1]] 21 | 22 | def mult(a, v): 23 | return [a[0]*v, a[1]*v] 24 | 25 | def div(a, v): 26 | return [a[0]/v, a[1]/v] 27 | 28 | def rotate(a, d): 29 | return [a[0]*cos(d)+a[1]*cos(pi/2+d), a[0]*sin(d)+a[1]*sin(pi/2+d)] 30 | 31 | def angle(x): 32 | return atan2(x[1], x[0]) 33 | 34 | def inside_colinear_segment(s, p): 35 | return inner_product(sub(p, s[0]), sub(p, s[1])) <= 0 36 | 37 | def segment(a, b): 38 | d = sub(b, a) 39 | return ((a, b), div(d, inner_product(d, d)**0.5)) 40 | 41 | def intersection(s, u, p, R_square): 42 | closet = add(s[0], mult(u, inner_product(sub(p, s[0]), u))) 43 | v = sub(p, closet) 44 | d_square = inner_product(v, v) 45 | result = [] 46 | if d_square <= R_square: 47 | l = (R_square-d_square)**0.5 48 | if l == 0: 49 | if inside_colinear_segment(s, closet): 50 | result.append(closet) 51 | else: 52 | p1 = add(closet, mult(u, l)) 53 | if inside_colinear_segment(s, p1): 54 | result.append(p1) 55 | p2 = add(closet, mult(u, -l)) 56 | if inside_colinear_segment(s, p2): 57 | result.append(p2) 58 | return result 59 | 60 | def cup_counterbalancing(): 61 | def check(p): # Time: O(N) 62 | angles = [angle(sub(x, p)) for s, u in segments for x in intersection(s, u, p, R_square)] 63 | a, b = [], [] 64 | mn_a = mn_b = pi 65 | mx_a = mx_b = -pi 66 | for x in angles: # write verbosely to improve performance 67 | if x < 0: 68 | if x < mn_a: 69 | mn_a = x 70 | if x > mx_a: 71 | mx_a = x 72 | a.append(x) 73 | else: 74 | if x < mn_b: 75 | mn_b = x 76 | if x > mx_b: 77 | mx_b = x 78 | b.append(x) 79 | return len(a) > 0 and len(b) > 0 and mn_b < mx_a+pi and mn_a+pi < mx_b 80 | 81 | N, R, L = map(int, input().split()) 82 | R_square = R**2 83 | points = [list(map(int, input().split())) for _ in range(N)] 84 | segments = [segment(points[i], points[(i+1)%len(points)]) for i in range(len(points))] 85 | u = mult(rotate((1, 0), random()*pi/4), L/SAMPLE**0.5) 86 | v = [-u[1], u[0]] 87 | total = good = 0 88 | for idx, (j, d) in enumerate(((0, 1), (-1, -1))): 89 | start = [0, 0] 90 | found = True 91 | while found: 92 | found = False 93 | i = 0 94 | curr = start 95 | while curr[0] <= L and curr[1] <= L: 96 | if 0 <= curr[idx]: 97 | found = True 98 | if check(curr): 99 | good += 1 100 | total += 1 101 | i += 1 102 | curr = add(start, mult(u, i)) 103 | j += d 104 | start = mult(v, j) 105 | return good/total 106 | 107 | seed(0) 108 | SAMPLE = 10**8 109 | for case in range(int(input())): 110 | print('Case #%d: %s' % (case+1, cup_counterbalancing())) 111 | -------------------------------------------------------------------------------- /Final Round/hazelnut_harvesting.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Final Round - Problem E. Hazelnut Harvesting 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/E 5 | # 6 | # Time: O(NlogN) 7 | # Space: O(NlogN) 8 | # 9 | 10 | class SegmentTree(object): 11 | def __init__(self, N, M): 12 | self.N = N 13 | self.tree = [[[], []] for _ in range(2*2**((N-1).bit_length()))] 14 | self.recs = [None for _ in range(M)] 15 | 16 | def update(self, l, r, v): 17 | def _update(i, L, R, l, r, v): 18 | self.tree[i][0].append(v) 19 | if (L, R) == (l, r): 20 | self.tree[i][1].append(v) 21 | return 22 | M = L+(R-L)//2 23 | if r <= M: 24 | _update(2*i, L, M, l, r, v) 25 | return 26 | if l >= M+1: 27 | _update(2*i+1, M+1, R, l, r, v) 28 | return 29 | _update(2*i, L, M, l, M, v) 30 | _update(2*i+1, M+1, R, M+1, r, v) 31 | 32 | return _update(1, 0, self.N-1, l, r, v) 33 | 34 | def query(self, l, r, v): 35 | def _query(i, L, R, l, r, v): 36 | while self.tree[i][1] and self.recs[self.tree[i][1][-1]][1] == -1: 37 | self.tree[i][1].pop() 38 | if self.tree[i][1] and self.recs[self.tree[i][1][-1]][1] >= v: 39 | return self.tree[i][1][-1] 40 | if (L, R) == (l, r): 41 | while self.tree[i][0] and self.recs[self.tree[i][0][-1]][1] == -1: 42 | self.tree[i][0].pop() 43 | if self.tree[i][0] and self.recs[self.tree[i][0][-1]][1] >= v: 44 | return self.tree[i][0][-1] 45 | return -1 46 | M = L+(R-L)//2 47 | if r <= M: 48 | return _query(2*i, L, M, l, r, v) 49 | if l >= M+1: 50 | return _query(2*i+1, M+1, R, l, r, v) 51 | l = _query(2*i, L, M, l, M, v) 52 | if l != -1: 53 | return l 54 | return _query(2*i+1, M+1, R, M+1, r, v) 55 | 56 | return _query(1, 0, self.N-1, l, r, v) 57 | 58 | def update_rec(self, i, rec): 59 | self.recs[i] = rec 60 | 61 | def hazelnut_harvesting(): 62 | N = int(input()) 63 | recs = [] 64 | x_set, y_set = set(), set() 65 | for _ in range(N): 66 | X, Y = map(int, input().split()) 67 | recs.append([X-1, X+1, Y-1, Y+1]) 68 | x_set.add(X-1), x_set.add(X+1) 69 | y_set.add(Y-1), y_set.add(Y+1) 70 | x_idx = {x:i for i, x in enumerate(sorted(x_set))} 71 | y_idx = {y:i for i, y in enumerate(sorted(y_set))} 72 | recs.sort(key=lambda x:x[0]) 73 | st = SegmentTree(len(y_idx), len(recs)) 74 | result = 0 75 | for i in range(len(recs)): 76 | while True: 77 | j = st.query(y_idx[recs[i][2]], y_idx[recs[i][3]], x_idx[recs[i][0]]) 78 | if j == -1: 79 | st.update(y_idx[recs[i][2]], y_idx[recs[i][3]], i) 80 | st.update_rec(i, [x_idx[recs[i][0]], x_idx[recs[i][1]], y_idx[recs[i][2]], y_idx[recs[i][3]]]) 81 | result += (recs[i][1]-recs[i][0])*(recs[i][3]-recs[i][2]) 82 | break 83 | result -= (recs[j][1]-recs[j][0])*(recs[j][3]-recs[j][2]) 84 | st.update_rec(j, [-1]*4) 85 | recs[i] = [min(recs[i][0], recs[j][0]), 86 | max(recs[i][1], recs[j][1]), 87 | min(recs[i][2], recs[j][2]), 88 | max(recs[i][3], recs[j][3])] 89 | st.update_rec(i, [x_idx[recs[i][0]], x_idx[recs[i][1]], y_idx[recs[i][2]], y_idx[recs[i][3]]]) 90 | return result 91 | 92 | for case in range(int(input())): 93 | print('Case #%d: %s' % (case+1, hazelnut_harvesting())) 94 | -------------------------------------------------------------------------------- /Final Round/tile_transposing.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Final Round - Problem C. Tile Transposing 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/C 5 | # 6 | # Time: O(M * N * log(M * N)), pass in PyPy3 but Python3 7 | # Space: O(M * N) 8 | # 9 | 10 | class PersistentUnionFind(object): # Time: O(n * alpha(n)), Space: O(n) 11 | def __init__(self, n): 12 | self.set = list(range(n)) 13 | self.size = [1]*n 14 | self.snapshots = [] # added 15 | self.undos = [] # added 16 | 17 | def find_set(self, x): 18 | stk = [] 19 | while self.set[x] != x: # path compression 20 | stk.append(x) 21 | x = self.set[x] 22 | while stk: 23 | y = stk.pop() 24 | self.undos.append((~y, self.set[y])) # added 25 | self.set[y] = x 26 | return x 27 | 28 | def union_set(self, x, y): 29 | x, y = self.find_set(x), self.find_set(y) 30 | if x == y: 31 | return False 32 | if self.size[x] > self.size[y]: # union by size 33 | x, y = y, x 34 | self.undos.append((x, y)) # added 35 | self.set[x] = self.set[y] 36 | self.size[y] += self.size[x] 37 | return True 38 | 39 | def total(self, x): 40 | return self.size[self.find_set(x)] 41 | 42 | def snapshot(self): # added 43 | self.snapshots.append(len(self.undos)) 44 | 45 | def rollback(self): # added 46 | for _ in range(len(self.undos)-self.snapshots.pop()): 47 | x, y = self.undos.pop() 48 | if x >= 0: 49 | self.size[y] -= self.size[x] 50 | self.set[x] = x 51 | else: 52 | self.set[~x] = y 53 | 54 | def tile_transposing(): 55 | def merge(i): 56 | r, c = divmod(i, C) 57 | for dr, dc in DIRECTIONS: 58 | nr, nc = r+dr, c+dc 59 | ni = nr*C+nc 60 | if 0 <= nr < R and 0 <= nc < C and G[ni] == G[i] and lookup[ni]: 61 | uf.union_set(i, ni) 62 | 63 | def clear(i): 64 | r, c = divmod(i, C) 65 | for dr, dc in DIRECTIONS: 66 | nr, nc = r+dr, c+dc 67 | ni = nr*C+nc 68 | if not (0 <= nr < R and 0 <= nc < C and G[ni] != G[i]): 69 | continue 70 | uf.snapshot() 71 | for dr, dc in DIRECTIONS: 72 | nnr, nnc = nr+dr, nc+dc 73 | nni = nnr*C+nnc 74 | if 0 <= nnr < R and 0 <= nnc < C and nni != i and G[nni] == G[i]: 75 | uf.union_set(i, nni) 76 | if uf.total(i) >= 3: 77 | result[0] += uf.total(i) 78 | uf.rollback() 79 | 80 | def dfs(left, right): 81 | if left == right: 82 | clear(left) 83 | return 84 | mid = left + (right-left)//2 85 | l1, r1, l2, r2 = left, mid, mid+1, right 86 | for _ in range(2): 87 | uf.snapshot() 88 | for i in range(l1, r1+1): 89 | lookup[i] = True 90 | merge(i) 91 | dfs(l2, r2) 92 | for i in range(l1, r1+1): 93 | lookup[i] = False 94 | uf.rollback() 95 | l1, r1, l2, r2 = l2, r2, l1, r1 96 | 97 | R, C = map(int, input().split()) 98 | G = [] 99 | for _ in range(R): 100 | G.extend(map(int, input().split())) 101 | uf = PersistentUnionFind(R*C) 102 | lookup = [False]*(R*C) 103 | result = [0] 104 | dfs(0, len(lookup)-1) 105 | return result[0]*2 106 | 107 | DIRECTIONS = ((1, 0), (0, 1), (-1, 0), (0, -1)) 108 | for case in range(int(input())): 109 | print('Case #%d: %s' % (case+1, tile_transposing())) 110 | -------------------------------------------------------------------------------- /Round 3/zero_crossings_chapter_1_2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 3 - Problem E1. Zero Crossings - Chapter 1 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/E1 5 | # 6 | # Time: O((N * M + Q) * log(N * M + Q)) 7 | # Space: O(N * M + Q) 8 | # 9 | 10 | from sortedcontainers import SortedList 11 | 12 | def cross(o, a, b): 13 | return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) 14 | 15 | class Edge(object): 16 | def __init__(self, a, b): 17 | assert(a <= b) 18 | self.a = a 19 | self.b = b 20 | 21 | def __repr__(self): 22 | return f"({self.a}, {self.b})" 23 | 24 | def __eq__(self, other): 25 | return (self.a, self.b) == (other.a, other.b) 26 | 27 | def __lt__(self, other): 28 | if self.a == other.a: 29 | return cross(self.a, self.b, other.b) > 0 30 | if other.a[0] <= self.a[0] < other.b[0]: 31 | return cross(other.a, self.a, other.b) > 0 32 | elif self.a[0] <= other.a[0] < self.b[0]: 33 | return cross(self.a, other.a, self.b) < 0 34 | assert(False) 35 | 36 | def iter_dfs1(adj): 37 | hashes = [None]*len(adj) 38 | stk = [(1, 0)] 39 | while stk: 40 | step, u = stk.pop() 41 | if step == 1: 42 | stk.append((2, u)) 43 | for v in reversed(adj[u]): 44 | stk.append((1, v)) 45 | elif step == 2: 46 | hashes[u] = hash(tuple(sorted(hashes[v] for v in adj[u]))) 47 | return hashes 48 | 49 | def iter_dfs2(adj, hashes): 50 | stk = [(0, None)] 51 | while stk: 52 | u, h = stk.pop() 53 | hashes[u] = hash((h, hashes[u])) 54 | for v in reversed(adj[u]): 55 | stk.append((v, hashes[u])) 56 | 57 | def find_parents(N, Q, events): 58 | def find_parent(e): 59 | _, idx, upper = sl[sl.bisect_right((e,))] 60 | return idx if upper else parent1[idx] 61 | 62 | parent1, parent2 = [-1]*(N+1), [-1]*(2*Q) 63 | sl = SortedList([(Edge((MIN_X_Y-1, MAX_X_Y+1), (MAX_X_Y+1, MAX_X_Y+1)), 0, True)]) 64 | for (_, t, _), idx, e, upper in events: 65 | if t == 0: 66 | sl.remove((e, idx, upper)) 67 | elif t == 1: 68 | if parent1[idx] == -1: 69 | parent1[idx] = find_parent(e) 70 | sl.add((e, idx, upper)) 71 | elif t == 2: 72 | parent2[idx] = find_parent(e) 73 | return parent1, parent2 74 | 75 | def zero_crossings_chapter_1(): 76 | N = int(input()) 77 | events = [] 78 | for idx in range(1, N+1): 79 | M = int(input()) 80 | X_Y = list(map(int, input().split())) 81 | V = [(X_Y[2*i], X_Y[2*i+1]) for i in range(M)] 82 | for i in range(M): 83 | a, b = V[i], V[(i+1)%M] 84 | if a[0] == b[0]: 85 | continue 86 | upper = True 87 | if a[0] > b[0]: 88 | upper = False 89 | a, b = b, a 90 | events.append(((a[0], 1, -a[1]), idx, Edge(a, b), upper)) 91 | events.append(((b[0], 0, -b[1]), idx, Edge(a, b), upper)) 92 | Q = int(input()) 93 | for idx in range(Q): 94 | A, B, C, D = map(int, input().split()) 95 | for i, a in enumerate([(A, B), (C, D)]): 96 | events.append(((a[0], 2, -a[1]), 2*idx+i, Edge(a, a), False)) 97 | events.sort(key=lambda x: x[0]) # sort by (a_x, t, -a_y) 98 | parent1, parent2 = find_parents(N, Q, events) 99 | adj = [[] for _ in range(N+1)] 100 | for i in range(1, N+1): 101 | adj[parent1[i]].append(i) 102 | hashes = iter_dfs1(adj) 103 | iter_dfs2(adj, hashes) 104 | return sum(hashes[parent2[2*idx]] == hashes[parent2[2*idx+1]] for idx in range(Q)) 105 | 106 | MIN_X_Y, MAX_X_Y = 0, 10**9 107 | for case in range(int(input())): 108 | print('Case #%d: %s' % (case+1, zero_crossings_chapter_1())) 109 | -------------------------------------------------------------------------------- /Round 3/zero_crossings_chapter_1.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 3 - Problem E1. Zero Crossings - Chapter 1 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/E1 5 | # 6 | # Time: O((N * M + Q) * log(N * M + Q)) 7 | # Space: O(N * M + Q) 8 | # 9 | 10 | from random import seed, random 11 | 12 | class TreapNode(object): 13 | def __init__(self, key): 14 | self.key = key 15 | self.prior = random() 16 | self.left = None 17 | self.right = None 18 | 19 | class Treap(object): 20 | def __init__(self): 21 | self.root = None 22 | 23 | def insert(self, key): 24 | self.root = self.__insert(self.root, key) 25 | 26 | def delete(self, key): 27 | self.root = self.__delete(self.root, key) 28 | 29 | def __insert(self, x, key): 30 | if not x: 31 | return TreapNode(key) 32 | if key < x.key: 33 | x.left = self.__insert(x.left, key) 34 | if x.left.prior < x.prior: 35 | return self.__rotate_left(x) 36 | elif x.key < key: 37 | x.right = self.__insert(x.right, key) 38 | if x.right.prior < x.prior: 39 | return self.__rotate_right(x) 40 | return x 41 | 42 | def __delete(self, x, key): 43 | if key < x.key: 44 | x.left = self.__delete(x.left, key) 45 | elif x.key < key: 46 | x.right = self.__delete(x.right, key) 47 | else: 48 | return self.__delete_node(x) 49 | return x 50 | 51 | def __delete_node(self, x): 52 | if x.left and x.right: 53 | if x.left.prior < x.right.prior: 54 | y = self.__rotate_left(x) 55 | y.right = self.__delete_node(x) 56 | else: 57 | y = self.__rotate_right(x) 58 | y.left = self.__delete_node(x) 59 | return y 60 | return x.right if x.right else x.left 61 | 62 | def __rotate_left(self, x): 63 | y = x.left 64 | x.left = y.right 65 | y.right = x 66 | return y 67 | 68 | def __rotate_right(self, x): 69 | y = x.right 70 | x.right = y.left 71 | y.left = x 72 | return y 73 | 74 | def cross(o, a, b): 75 | return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) 76 | 77 | class Edge(object): 78 | def __init__(self, a, b): 79 | assert(a <= b) 80 | self.a = a 81 | self.b = b 82 | 83 | def __repr__(self): 84 | return f"({self.a}, {self.b})" 85 | 86 | def __eq__(self, other): 87 | return (self.a, self.b) == (other.a, other.b) 88 | 89 | def __lt__(self, other): 90 | if self.a == other.a: 91 | return cross(self.a, self.b, other.b) > 0 92 | if other.a[0] <= self.a[0] < other.b[0]: 93 | return cross(other.a, self.a, other.b) > 0 94 | elif self.a[0] <= other.a[0] < self.b[0]: 95 | return cross(self.a, other.a, self.b) < 0 96 | assert(False) 97 | 98 | def iter_dfs1(adj): 99 | hashes = [None]*len(adj) 100 | stk = [(1, 0)] 101 | while stk: 102 | step, u = stk.pop() 103 | if step == 1: 104 | stk.append((2, u)) 105 | for v in reversed(adj[u]): 106 | stk.append((1, v)) 107 | elif step == 2: 108 | hashes[u] = hash(tuple(sorted(hashes[v] for v in adj[u]))) 109 | return hashes 110 | 111 | def iter_dfs2(adj, hashes): 112 | stk = [(0, None)] 113 | while stk: 114 | u, h = stk.pop() 115 | hashes[u] = hash((h, hashes[u])) 116 | for v in reversed(adj[u]): 117 | stk.append((v, hashes[u])) 118 | 119 | def bisect_right(node, x): 120 | result = None 121 | while node: 122 | if x < node.key: 123 | result = node 124 | node = node.left 125 | else: 126 | node = node.right 127 | return result 128 | 129 | def find_parents(N, Q, events): 130 | def find_parent(e): 131 | _, idx, upper = bisect_right(tp.root, (e,)).key 132 | return idx if upper else parent1[idx] 133 | 134 | parent1, parent2 = [-1]*(N+1), [-1]*(2*Q) 135 | tp = Treap() 136 | tp.insert((Edge((MIN_X_Y-1, MAX_X_Y+1), (MAX_X_Y+1, MAX_X_Y+1)), 0, True)) 137 | for (_, t, _), idx, e, upper in events: 138 | if t == 0: 139 | tp.delete((e, idx, upper)) 140 | elif t == 1: 141 | if parent1[idx] == -1: 142 | parent1[idx] = find_parent(e) 143 | tp.insert((e, idx, upper)) 144 | elif t == 2: 145 | parent2[idx] = find_parent(e) 146 | return parent1, parent2 147 | 148 | def zero_crossings_chapter_1(): 149 | N = int(input()) 150 | events = [] 151 | for idx in range(1, N+1): 152 | M = int(input()) 153 | X_Y = list(map(int, input().split())) 154 | V = [(X_Y[2*i], X_Y[2*i+1]) for i in range(M)] 155 | for i in range(M): 156 | a, b = V[i], V[(i+1)%M] 157 | if a[0] == b[0]: 158 | continue 159 | upper = True 160 | if a[0] > b[0]: 161 | upper = False 162 | a, b = b, a 163 | events.append(((a[0], 1, -a[1]), idx, Edge(a, b), upper)) 164 | events.append(((b[0], 0, -b[1]), idx, Edge(a, b), upper)) 165 | Q = int(input()) 166 | for idx in range(Q): 167 | A, B, C, D = map(int, input().split()) 168 | for i, a in enumerate([(A, B), (C, D)]): 169 | events.append(((a[0], 2, -a[1]), 2*idx+i, Edge(a, a), False)) 170 | events.sort(key=lambda x: x[0]) # sort by (a_x, t, -a_y) 171 | parent1, parent2 = find_parents(N, Q, events) 172 | adj = [[] for _ in range(N+1)] 173 | for i in range(1, N+1): 174 | adj[parent1[i]].append(i) 175 | hashes = iter_dfs1(adj) 176 | iter_dfs2(adj, hashes) 177 | return sum(hashes[parent2[2*idx]] == hashes[parent2[2*idx+1]] for idx in range(Q)) 178 | 179 | seed(0) 180 | MIN_X_Y, MAX_X_Y = 0, 10**9 181 | for case in range(int(input())): 182 | print('Case #%d: %s' % (case+1, zero_crossings_chapter_1())) 183 | -------------------------------------------------------------------------------- /Round 3/zero_crossings_chapter_2.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Round 3 - Problem E2. Zero Crossings - Chapter 2 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/E2 5 | # 6 | # Time: O((N * M) * log(N * M) + Q * log(N * M)), pass in PyPy3 but Python3 7 | # Space: O((N * M) * log(N * M)) 8 | # 9 | 10 | from random import seed, random 11 | from copy import copy 12 | from bisect import bisect_left 13 | 14 | class TreapNode(object): 15 | def __init__(self, key): 16 | self.key = key 17 | self.prior = random() 18 | self.left = None 19 | self.right = None 20 | 21 | class PersistentTreap(object): 22 | def __init__(self): 23 | self.root = None 24 | 25 | def insert(self, key): 26 | self.root = self.__insert(self.root, key) 27 | 28 | def delete(self, key): 29 | self.root = self.__delete(self.root, key) 30 | 31 | def __insert(self, x, key): 32 | if not x: 33 | return TreapNode(key) 34 | y = copy(x) 35 | if key < y.key: 36 | y.left = self.__insert(y.left, key) 37 | if y.left.prior < y.prior: 38 | return self.__rotate_left(y) 39 | elif y.key < key: 40 | y.right = self.__insert(y.right, key) 41 | if y.right.prior < y.prior: 42 | return self.__rotate_right(y) 43 | return y 44 | 45 | def __delete(self, x, key): 46 | y = copy(x) 47 | if key < y.key: 48 | y.left = self.__delete(y.left, key) 49 | elif y.key < key: 50 | y.right = self.__delete(y.right, key) 51 | else: 52 | return self.__delete_node(y) 53 | return y 54 | 55 | def __delete_node(self, x): 56 | if x.left and x.right: 57 | if x.left.prior < x.right.prior: 58 | x.left = copy(x.left) 59 | y = self.__rotate_left(x) 60 | y.right = self.__delete_node(x) 61 | else: 62 | x.right = copy(x.right) 63 | y = self.__rotate_right(x) 64 | y.left = self.__delete_node(x) 65 | return y 66 | return x.right if x.right else x.left 67 | 68 | def __rotate_left(self, x): 69 | y = x.left 70 | x.left = y.right 71 | y.right = x 72 | return y 73 | 74 | def __rotate_right(self, x): 75 | y = x.right 76 | x.right = y.left 77 | y.left = x 78 | return y 79 | 80 | def cross(o, a, b): 81 | return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) 82 | 83 | class Edge(object): 84 | def __init__(self, a, b): 85 | assert(a <= b) 86 | self.a = a 87 | self.b = b 88 | 89 | def __repr__(self): 90 | return f"({self.a}, {self.b})" 91 | 92 | def __eq__(self, other): 93 | return (self.a, self.b) == (other.a, other.b) 94 | 95 | def __lt__(self, other): 96 | if self.a == other.a: 97 | return cross(self.a, self.b, other.b) > 0 98 | if other.a[0] <= self.a[0] < other.b[0]: 99 | return cross(other.a, self.a, other.b) > 0 100 | elif self.a[0] <= other.a[0] < self.b[0]: 101 | return cross(self.a, other.a, self.b) < 0 102 | assert(False) 103 | 104 | def bisect_right(node, x): 105 | result = None 106 | while node: 107 | if x < node.key: 108 | result = node 109 | node = node.left 110 | else: 111 | node = node.right 112 | return result 113 | 114 | def iter_dfs1(adj): 115 | hashes = [None]*len(adj) 116 | stk = [(1, 0)] 117 | while stk: 118 | step, u = stk.pop() 119 | if step == 1: 120 | stk.append((2, u)) 121 | for v in reversed(adj[u]): 122 | stk.append((1, v)) 123 | elif step == 2: 124 | hashes[u] = hash(tuple(sorted(hashes[v] for v in adj[u]))) 125 | return hashes 126 | 127 | def iter_dfs2(adj, hashes): 128 | stk = [(0, None)] 129 | while stk: 130 | u, h = stk.pop() 131 | hashes[u] = hash((h, hashes[u])) 132 | for v in reversed(adj[u]): 133 | stk.append((v, hashes[u])) 134 | 135 | def find_root(roots, a): 136 | return roots[bisect_left(roots, (a[0]+1,))-1][1] 137 | 138 | def find_parent(parent, root, e): 139 | _, idx, upper = bisect_right(root, (e,)).key 140 | return idx if upper else parent[idx] 141 | 142 | def find_parents(N, events): 143 | parent = [-1]*(N+1) 144 | pt = PersistentTreap() 145 | pt.insert((Edge((MIN_X_Y-1, MAX_X_Y+1), (MAX_X_Y+1, MAX_X_Y+1)), 0, True)) 146 | roots = [(MIN_X_Y-1, pt.root)] 147 | for (a_x, t, _), idx, e, upper in events: 148 | if t == 0: 149 | pt.delete((e, idx, upper)) 150 | elif t == 1: 151 | if parent[idx] == -1: 152 | parent[idx] = find_parent(parent, pt.root, e) 153 | pt.insert((e, idx, upper)) 154 | roots.append((a_x, pt.root)) 155 | return parent, roots 156 | 157 | def zero_crossings_chapter_2(): 158 | N = int(input()) 159 | events = [] 160 | for idx in range(1, N+1): 161 | M = int(input()) 162 | X_Y = list(map(int, input().split())) 163 | V = [(X_Y[2*i], X_Y[2*i+1]) for i in range(M)] 164 | for i in range(M): 165 | a, b = V[i], V[(i+1)%M] 166 | if a[0] == b[0]: 167 | continue 168 | upper = True 169 | if a[0] > b[0]: 170 | upper = False 171 | a, b = b, a 172 | events.append(((a[0], 1, -a[1]), idx, Edge(a, b), upper)) 173 | events.append(((b[0], 0, -b[1]), idx, Edge(a, b), upper)) 174 | events.sort(key=lambda x: x[0]) # sort by (a_x, t, -a_y) 175 | parent, roots = find_parents(N, events) 176 | adj = [[] for _ in range(N+1)] 177 | for i in range(1, N+1): 178 | adj[parent[i]].append(i) 179 | hashes = iter_dfs1(adj) 180 | iter_dfs2(adj, hashes) 181 | result = R_E = 0 182 | Q = int(input()) 183 | for _ in range(Q): 184 | A, B, C, D, E = map(int, input().split()) 185 | a, b = (A^R_E, B^R_E), (C^R_E, D^R_E) 186 | R = int(hashes[find_parent(parent, find_root(roots, a), Edge(a, a))] == 187 | hashes[find_parent(parent, find_root(roots, b), Edge(b, b))]) 188 | result += R 189 | R_E ^= R*E 190 | return result 191 | 192 | seed(0) 193 | MIN_X_Y, MAX_X_Y = 0, 10**9 194 | for case in range(int(input())): 195 | print('Case #%d: %s' % (case+1, zero_crossings_chapter_2())) 196 | -------------------------------------------------------------------------------- /Final Round/alphabet_adventuring.py3: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 kamyu. All rights reserved. 2 | # 3 | # Meta Hacker Cup 2022 Final Round - Problem D. Alphabet Adventuring 4 | # https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/D 5 | # 6 | # Time: O((R^2 + log(N + Q)) * (N + Q) + Q * (R^2 + log(N + Q))* log(N + Q)) 7 | # Space: O((R^2 + log(N + Q)) * (N + Q)) 8 | # 9 | 10 | from functools import partial 11 | 12 | # Template: 13 | # https://github.com/kamyu104/GoogleKickStart-2020/blob/main/Round%20D/locked_doors.py 14 | class TreeInfos(object): # Time: O(NlogN), Space: O(NlogN), N is the number of nodes 15 | def __init__(self, adj, edges): 16 | def divide(u, p): 17 | def update_up(u, p): 18 | if p == -1: 19 | return 20 | eid = edge_id[u, p] 21 | if not P[p]: 22 | up[eid] = [eid]*(26*26) 23 | return 24 | up[eid] = up[edge_id[p, P[p][0]]][:] 25 | for v, c in adj[p]: 26 | if v == P[p][0] or v == u: 27 | continue 28 | up[eid][c*26+par_c[p]] = eid 29 | 30 | if p != -1: 31 | P[u].append(p) # ancestors of the node i 32 | D[u] = D[p]+1 33 | i = 0 34 | while i < len(P[u]) and i < len(P[P[u][i]]): 35 | P[u].append(P[P[u][i]][i]) 36 | i += 1 37 | update_up(u, p) # added 38 | stk.append(partial(postprocess, u, p)) 39 | for v, c in adj[u]: 40 | if v == p: 41 | continue 42 | par_c[v] = c # added 43 | stk.append(partial(divide, v, u)) 44 | 45 | def postprocess(u, p): 46 | def update_down(u, p): 47 | nv, nc = heavy_child[u], heavy_c[u] 48 | if nv == -1: 49 | down[u] = [u]*(26*26) 50 | return 51 | down[u] = down[nv][:] 52 | for v, c in adj[u]: 53 | if v == nv or v == p: 54 | continue 55 | down[u][c*26+nc] = u 56 | 57 | def update_heavy(u, p): 58 | mx = 0 59 | for v, c in adj[u]: 60 | if v == p: 61 | continue 62 | size[u] += size[v] 63 | if size[v] > mx: 64 | mx = size[v] 65 | heavy_descent[u], heavy_child[u], heavy_c[u] = heavy_descent[v], v, c 66 | 67 | update_heavy(u, p) # added 68 | update_down(u, p) # added 69 | 70 | N = len(adj) 71 | D, P = [0]*N, [[] for _ in range(N)] 72 | 73 | # added 74 | size = [1]*N 75 | par_c, heavy_c, heavy_child = [[-1]*N for _ in range(3)] 76 | heavy_descent, ancestor = list(range(N)), list(range(N)) 77 | up = [None for _ in range(len(edges))] 78 | down = [None for _ in range(N)] 79 | edge_id = {(u, v): i for i, (u, v) in enumerate(edges)} 80 | 81 | stk = [] 82 | stk.append(partial(divide, 0, -1)) 83 | while stk: 84 | stk.pop()() 85 | 86 | self.adj = adj 87 | self.D, self.P = D, P 88 | 89 | # added 90 | self.edges = edges 91 | self.par_c, self.heavy_c, self.heavy_child = par_c, heavy_c, heavy_child 92 | self.heavy_descent, self.ancestor = heavy_descent, ancestor 93 | self.up, self.down = up, down 94 | self.edge_id = edge_id 95 | 96 | def __get_ancestor(self, u): 97 | stk = [] 98 | while self.ancestor[u] != u: 99 | stk.append(u) 100 | u = self.ancestor[u] 101 | for x in stk: 102 | self.ancestor[x] = u 103 | return u 104 | 105 | def __get_up_edge(self, eid, pid): 106 | stk = [] 107 | while self.up[eid][pid] != eid: 108 | stk.append(eid) 109 | eid = self.up[eid][pid] 110 | for x in stk: 111 | self.up[x][pid] = eid 112 | return eid 113 | 114 | def remove(self, u): 115 | p = self.P[u][0] 116 | self.ancestor[u] = self.__get_ancestor(p) 117 | if not self.P[p]: 118 | return 119 | c = next(c for v, c in self.adj[p] if v == u) 120 | par_eid = self.edge_id[p, self.P[p][0]] 121 | for v, _ in self.adj[p]: 122 | if v == self.P[p][0] or v != self.ancestor[v]: 123 | continue 124 | pid = c*26+self.par_c[p] 125 | self.up[self.edge_id[v, p]][pid] = self.__get_up_edge(par_eid, pid) 126 | 127 | def query(self, u, k, s): 128 | def binary_lift(u, k): 129 | for i in reversed(range(len(self.P[u]))): 130 | if k&(1< rank[c]: 142 | return u, k 143 | eid, v = self.edge_id[u, p], 0 144 | for pid in stops: 145 | _, nv = self.edges[self.__get_up_edge(eid, pid)] 146 | if self.D[nv] > self.D[v]: 147 | v = nv 148 | diff = self.D[u]-self.D[v] 149 | if k <= diff: 150 | u = binary_lift(u, k) 151 | return u, 0 152 | k -= diff 153 | u, prev_u = v, binary_lift(u, diff-1) 154 | v, c = -1, 26 155 | for nv, nc in self.adj[u]: 156 | if (self.P[u] and nv == self.P[u][0]) or nv == prev_u or nv != self.ancestor[nv]: 157 | continue 158 | if rank[nc] < c: 159 | c, v = rank[nc], nv 160 | if v == -1: 161 | return u, 0 162 | k -= 1 163 | u = v 164 | return u, k 165 | 166 | def go_down(u, k): 167 | while k: 168 | if self.heavy_child[u] == -1: 169 | break 170 | v = self.heavy_descent[u] 171 | for pid in stops: 172 | nv = self.down[u][pid] 173 | if self.D[nv] < self.D[v]: 174 | v = nv 175 | v = self.__get_ancestor(v) 176 | diff = self.D[v]-self.D[u] 177 | if k <= diff: 178 | v = binary_lift(v, diff-k) 179 | return v, 0 180 | k -= diff 181 | nv, nc = -1, 26 182 | for nnv, nnc in self.adj[v]: 183 | if (self.P[v] and nnv == self.P[v][0]) or nnv != self.ancestor[nnv]: 184 | continue 185 | if rank[nnc] < nc: 186 | nc, nv = rank[nnc], nnv 187 | if nv == -1: 188 | return v, 0 189 | k -= 1 190 | u = nv 191 | return u, k 192 | 193 | stops = [s[i]*26+s[j] for i in range(len(s)) for j in range(i+1, len(s))] 194 | rank = [0]*26 195 | for i, c in enumerate(s): 196 | rank[c] = i 197 | u, k = go_up(u, k) 198 | return go_down(u, k)[0] 199 | 200 | def alphabet_adventuring(): 201 | N = int(input()) 202 | adj = [[] for _ in range(N)] 203 | edges = [] 204 | for _ in range(N-1): 205 | u, v, c = input().split() 206 | u, v, c = int(u)-1, int(v)-1, ord(c)-ord('A') 207 | adj[u].append((v, c)) 208 | adj[v].append((u, c)) 209 | edges.append((u, v)) 210 | edges.append((v, u)) 211 | Q = int(input()) 212 | queries = [] 213 | for _ in range(Q): 214 | args = input().split() 215 | if args[0] == '1': 216 | adj.append([]) 217 | u, v, c = len(adj)-1, int(args[1])-1, ord(args[2])-ord('A') 218 | adj[u].append((v, c)) 219 | adj[v].append((u, c)) 220 | edges.append((u, v)) 221 | edges.append((v, u)) 222 | queries.append((u,)) 223 | else: 224 | queries.append((int(args[1])-1, int(args[2]), list(map(lambda x: ord(x)-ord('A'), args[3])))) 225 | tree = TreeInfos(adj, edges) 226 | result = [] 227 | for args in reversed(queries): 228 | if len(args) == 1: 229 | u = args[0] 230 | tree.remove(u) 231 | else: 232 | u, k, s = args 233 | result.append(tree.query(u, k, s)+1) 234 | return " ".join(map(str, reversed(result))) 235 | 236 | for case in range(int(input())): 237 | print('Case #%d: %s' % (case+1, alphabet_adventuring())) 238 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [MetaHackerCup-2022](https://www.facebook.com/hackercup/past_rounds/) ![Language](https://img.shields.io/badge/language-Python3-orange.svg) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) ![Progress](https://img.shields.io/badge/progress-30%20%2F%2030-ff69b4.svg) ![Visitors](https://visitor-badge.laobi.icu/badge?page_id=kamyu104.metahackercup.2022) 2 | 3 | * Python3 solutions of Meta Hacker Cup 2022. Solution begins with `*` means it will get TLE in the largest data set. 4 | * Total computation amount > `10^8`, which is not friendly for Python3 to solve in 5 ~ 15 seconds. A `6-minute` timer is set for uploading the result this year. 5 | * A problem was marked as `Very Hard` means that it was an unsolved one during the contest and may not be that difficult. 6 | 7 | 8 | ## Rounds 9 | 10 | * [Hacker Cup 2021](https://github.com/kamyu104/FacebookHackerCup-2021) 11 | * [Qualification Round](https://github.com/kamyu104/MetaHackerCup-2022#qualification-round) 12 | * [Round 1](https://github.com/kamyu104/MetaHackerCup-2022#round-1) 13 | * [Round 2](https://github.com/kamyu104/MetaHackerCup-2022#round-2) 14 | * [Round 3](https://github.com/kamyu104/MetaHackerCup-2022#round-3) 15 | * [Final Round](https://github.com/kamyu104/MetaHackerCup-2022#final-round) 16 | * [Hacker Cup 2023](https://github.com/kamyu104/MetaHackerCup-2023) 17 | 18 | ## Qualification Round 19 | | # | Title | Solution | Time | Space | Difficulty | Tag | Note | 20 | |---| ----- | -------- | ---- | ----- | ---------- | --- | ---- | 21 | |A| [Second Hands](https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/A)| [Python3](./Qualification%20Round/second_hands.py3) | _O(N)_ | _O(N)_ | Easy | | Greedy | 22 | |B1| [Second Friend](https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/B1)| [Python3](./Qualification%20Round/second_friend.py3) | _O(R * C)_ | _O(1)_ | Easy | | Constructive Algorithms | 23 | |B2| [Second Second Friend](https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/B2)| [Python3](./Qualification%20Round/second_second_friend.py3) | _O(R * C)_ | _O(R * C)_ | Medium | | Constructive Algorithms, BFS | 24 | |C1| [Second Meaning](https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/C1)| [Python3](./Qualification%20Round/second_meaning.py3) | _O(N^2)_ | _O(N)_ | Easy | | Constructive Algorithms | 25 | |C2| [Second Second Meaning](https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/C2)| [Python3](./Qualification%20Round/second_second_meaning.py3) | _O(NlogN)_ | _O(logN)_ | Medium | | Constructive Algorithms | 26 | |D| [Second Flight](https://www.facebook.com/codingcompetitions/hacker-cup/2022/qualification-round/problems/D)| [Python3](./Qualification%20Round/second_flight.py3) [Python3](./Qualification%20Round/second_flight2.py3) | _O(N + Q + M * min(sqrt(Q), N))_ | _O(N + M + Q)_ | Hard | | Graph, Memoization | 27 | 28 | ## Round 1 29 | | # | Title | Solution | Time | Space | Difficulty | Tag | Note | 30 | |---| ----- | -------- | ---- | ----- | ---------- | --- | ---- | 31 | |A1| [Consecutive Cuts - Chapter 1](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/A1)| [Python3](./Round%201/consecutive_cuts_chapter_1.py3) | _O(N)_ | _O(1)_ | Easy | | Constructive Algorithms, String | 32 | |A2| [Consecutive Cuts - Chapter 2](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/A2)| [Python3](./Round%201/consecutive_cuts_chapter_2.py3) [Python3](./Round%201/consecutive_cuts_chapter_2-2.py3) [Python3](./Round%201/consecutive_cuts_chapter_2-3.py3) | _O(N)_ | _O(1)_ | Medium | | Constructive Algorithms, String, KMP Algorithm, Z-Function, Rabin-Karp Algorithm, Rolling Hash | 33 | |B1| [Watering Well - Chapter 1](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/B1)| [Python3](./Round%201/watering_well_chapter_1.py3) | _O(N + Q + min(N * Q, MAX_A_B_X_Y^2))_ | _O(min(N + Q, MAX_A_B_X_Y))_ | Easy | | Math, Freq Table | 34 | |B2| [Watering Well - Chapter 2](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/B2)| [Python3](./Round%201/watering_well_chapter_2.py3) | _O(N + Q)_ | _O(1)_ | Easy | | Math | 35 | |C| [Lemonade Life](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-1/problems/C)| [PyPy3](./Round%201/lemonade_life.py3) | _O(NlogN + V^2)_ | _O(N + V)_ | Hard | | Geometry, Convex Hull, Monotone Chain Algorithm, Graph, Dijkstra's Algorithm | 36 | 37 | ## Round 2 38 | | # | Title | Solution | Time | Space | Difficulty | Tag | Note | 39 | |---| ----- | -------- | ---- | ----- | ---------- | --- | ---- | 40 | |A1| [Perfectly Balanced - Chapter 1](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/A1)| [Python3](./Round%202/perfectly_balanced_chapter_1.py3) | _O(N + Q)_ | _O(N)_ | Easy | | Prefix Sum | 41 | |A2| [Perfectly Balanced - Chapter 2](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/A2)| [Python3](./Round%202/perfectly_balanced_chapter_2.py3) | _O((N + Q) * logN)_ | _O(N)_ | Medium | | Hash, BIT, Fenwick Tree | 42 | |B| [Balance Sheet](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/B)| [Python3](./Round%202/balance_sheet.py3) | _O(NlogN + N * K)_ | _O(N * K)_ | Medium | | Sort, Greedy, DP | 43 | |C| [Balance Scale](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/C)| [Python3](./Round%202/balance_scale.py3) | precompute: _O(MAX\_N * MAX\_C)_
runtime: _O(N)_ | precompute: _O(MAX\_N * MAX\_C)_
runtime: _O(1)_ | Easy | | Combinatorics, Probability | 44 | |D1| [Work-Life Balance - Chapter 1](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/D1)| [Python3](./Round%202/work_life_balance_chapter_1.py3) | _O((N + M) * logN)_ | _O(N)_ | Medium | | BIT, Fenwick Tree, Greedy | 45 | |D2| [Work-Life Balance - Chapter 2](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-2/problems/D2)| [Python3](./Round%202/work_life_balance_chapter_2.py3) | _O((N + M) * logN)_ | _O(N)_ | Hard | | BIT, Fenwick Tree, Greedy | 46 | 47 | ## Round 3 48 | | # | Title | Solution | Time | Space | Difficulty | Tag | Note | 49 | |---| ----- | -------- | ---- | ----- | ---------- | --- | ---- | 50 | |A| [Fourth Player](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/A)| [Python3](./Round%203/fourth_player.py3) | _O(NlogN)_ | _O(N)_ | Medium | | Games, Greedy | 51 | |B| [Third Trie](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/B)| [Python3](./Round%203/third_trie.py3) | _O(N * M)_ | _O(T)_ | Easy | | Trie, Combinatorics | 52 | |C| [Second Mistake](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/C)| [Python3](./Round%203/second_mistake.py3) | _O(3 * L * (N + Q))_ | _O(3 * L * N)_ | Easy | | Rabin-Karp Algorithm, Hash Table | 53 | |D1| [First Time - Chapter 1](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/D1)| [Python3](./Round%203/first_time_chapter_1.py3) | _O(M + NlogN)_ | _O(N)_ | Medium | | Unordered Set | 54 | |D2| [First Time - Chapter 2](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/D2)| [Python3](./Round%203/first_time_chapter_2.py3) | _O(M + NlogN)_ | _O(N)_ | Hard | | Unordered Set, Segment Tree, Number Theory | 55 | |E1| [Zero Crossings - Chapter 1](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/E1)| [Python3](./Round%203/zero_crossings_chapter_1.py3) [Python3](./Round%203/zero_crossings_chapter_1_2.py3) | _O((N * M + Q) * log(N * M + Q))_ | _O(N * M + Q)_ | Hard | | Offline Solution, Geometry, Sort, Line Sweep, Treap, Sorted List, Binary Search, Tree, DFS, Hash | 56 | |E2| [Zero Crossings - Chapter 2](https://www.facebook.com/codingcompetitions/hacker-cup/2022/round-3/problems/E2)| [PyPy3](./Round%203/zero_crossings_chapter_2.py3) | _O((N * M) * log(N * M) + Q * log(N * M))_ | _O((N * M) * log(N * M)_ | Hard | | Online Solution, Geometry, Sort, Line Sweep, Persistent Treap, Binary Search, Tree, DFS, Hash | 57 | 58 | ## Final Round 59 | You can relive the magic of the 2022 Hacker Cup World Finals by watching the [Live Stream Recording](https://www.facebook.com/hackercup/videos/513912190802808) of the announcement of winners. 60 | 61 | | # | Title | Solution | Time | Space | Difficulty | Tag | Note | 62 | |---| ----- | -------- | ---- | ----- | ---------- | --- | ---- | 63 | |A| [ML Modeling](https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/A)| [PyPy3](./Final%20Round/ml_modeling.py3) | _O(MAX_X * MAX_Y * MAX_R * MIN_N + (MAX_X * MAX_Y)^2 + N)_ | _O(MAX_X * MAX_Y)_ | Medium | | Geometry, Sampling | 64 | |B| [Emerald Exhibiting](https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/B)| [PyPy3](./Final%20Round/emerald_exhibiting.py3) | _O(P * logN)_ | _O(MAX_N)_ | Medium | | Combinatorics, Number Theory | 65 | |C| [Tile Transposing](https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/C)| [PyPy3](./Final%20Round/tile_transposing.py3) [PyPy3](./Final%20Round/tile_transposing2.py3) | _O(M * N * log(M * N))_ | _O(M * N)_ | Hard | | DFS, Persistent Union Find | 66 | |D| [Alphabet Adventuring](https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/D)| [Python3](./Final%20Round/alphabet_adventuring.py3) | _O((R^2 + log(N + Q)) * (N + Q) + Q * (R^2 + log(N + Q))* log(N + Q))_ | _O((R^2 + log(N + Q)) * (N + Q))_ | Hard | | Tree Traversal, Tree Ancestors (Binary Lifting), Heavy-Light Decomposition, Path Compression | 67 | |E| [Hazelnut Harvesting](https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/E)| [Python3](./Final%20Round/hazelnut_harvesting.py3) | _O(NlogN)_ | _O(NlogN)_ | Hard | | Coordinate Compression, Segment Tree, Line Sweep, Mono Stack | 68 | |F| [Cup Counterbalancing](https://www.facebook.com/codingcompetitions/hacker-cup/2022/final-round/problems/F)| [PyPy3](./Final%20Round/cup_counterbalancing.py3) | _O(N * S)_ | _O(N)_ | Very Hard | | Geometry, Sampling | 69 | --------------------------------------------------------------------------------