-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathspooky_splits.py3
73 lines (67 loc) · 2.42 KB
/
spooky_splits.py3
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
65
66
67
68
69
70
71
72
73
# Copyright (c) 2023 kamyu. All rights reserved.
#
# Meta Hacker Cup 2023 Round 3 - Problem A. Spooky Splits
# https://www.facebook.com/codingcompetitions/hacker-cup/2023/round-3/problems/A
#
# Time: O(D * S * sqrt(N)) = O(S * sqrt(N) * logN), D = len(divisors(N)) = O(logN) on average, S = number of visited states <= number of all possible states = sum(len(partitions(i)) for i in range(1, N+1)) = 1,642,992,567 if N = 100, in fact, S is much smaller than this number
# Space: O(S * sqrt(N))
#
from collections import Counter
def spooky_splits():
def bfs(u):
result = 0
lookup[u] = True
q = [u]
while q:
new_q = []
result += len(q)
for u in q:
for v in adj[u]:
if lookup[v]:
continue
lookup[v] = True
new_q.append(v)
q = new_q
return result
def check(K, N):
def backtracking(i, total, curr):
if total == N-target:
return True
fs = frozenset(curr.items())
if fs in lookup:
return False
lookup.add(fs)
for j in range(i, len(sorted_cnts)):
k = sorted_cnts[j]
if not (total%target+k <= target):
break
if not ((curr[k] if k in curr else 0)+1 <= cnts[k]):
continue
curr[k] += 1
if backtracking(j if (total+k)%target else 0, total+k, curr):
return True
curr[k] -= 1
if not curr[k]:
del curr[k]
return False
if N%K:
return False
target = N//K
if target < sorted_cnts[-1]:
return False
lookup = set()
return backtracking(0, 0, Counter())
N, M = list(map(int, input().split()))
A_B = [list(map(lambda x: int(x)-1, input().split())) for _ in range(M)]
adj = [[] for _ in range(N)]
for u, v in A_B:
adj[u].append(v)
adj[v].append(u)
lookup = [False]*N
cnts = Counter(bfs(u) for u in range(N) if not lookup[u])
assert(len(cnts)**2 < 2*N)
sorted_cnts = [k for k in range(1, N+1) if k in cnts]
result = [K for K in range(1, N+1) if check(K, N)]
return " ".join(map(str, result))
for case in range(int(input())):
print('Case #%d: %s' % (case+1, spooky_splits()))