-
Notifications
You must be signed in to change notification settings - Fork 13
/
bitstrings_as_a_service.py
64 lines (56 loc) · 2.29 KB
/
bitstrings_as_a_service.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# Copyright (c) 2019 kamyu. All rights reserved.
#
# Facebook Hacker Cup 2019 Round 2 - Bitstrings as a Service
# https://www.facebook.com/hackercup/problem/294773441466017/
#
# Time: O((M + N) * N)
# Space: O(N^2)
#
from collections import Counter
class UnionFind(object):
def __init__(self, n):
self.set = range(n)
def find_set(self, x):
if self.set[x] != x:
self.set[x] = self.find_set(self.set[x]) # path compression.
return self.set[x]
def union_set(self, x, y):
x_root, y_root = map(self.find_set, (x, y))
if x_root == y_root:
return False
self.set[min(x_root, y_root)] = max(x_root, y_root)
return True
def bitstrings_as_a_service():
N, M = map(int, raw_input().strip().split())
union_find = UnionFind(N)
for _ in xrange(M): # Time: O(M * N)
i, j = map(int, raw_input().strip().split())
i, j = i-1, j-1
while i <= j: # at most O(N) times
union_find.union_set(i, j)
i += 1
j -= 1
comps = Counter(map(union_find.find_set, range(N)))
dp = [[-1 for _ in xrange(N+1)] for _ in xrange(len(comps)+1)] # Space: O(N^2), dp[i][j] means the back link of
# the first i component with j nodes labeled 1,
# -1 means impossible
dp[0][0] = 0
for i, count in enumerate(comps.itervalues()): # Time: O(N^2)
for j in xrange(N):
if dp[i][j] != -1:
dp[i+1][j] = j # the first i+1 component is possible with j nodes labeled 1
dp[i+1][j+count] = j # the first i+1 component is also possible with (j + (i+1)_th_comp_size) nodes labeled 1
for j in xrange((N+1)//2, N+1): # find the min diff
if dp[-1][j] != -1:
assert(dp[-1][N-j] != -1)
break
labels = {}
for i, set_id in enumerate(reversed(comps.keys())): # back tracing
labels[set_id] = 1 if dp[-1-i][j] != j else 0
j = dp[-1-i][j]
result = []
for i in xrange(N):
result.append(labels[union_find.find_set(i)])
return "".join(map(str, result))
for case in xrange(input()):
print 'Case #%d: %s' % (case+1, bitstrings_as_a_service())