Here is the contest link. All problems are from Codeforces' Problemset.
A. Friendship is magic!^^
Keep two counters, one for Mishka and one for Chris. For each round, compare the two dice values and if Mishka’s is higher, increment her counter; if Chris’s is higher, increment his. At the end, compare the totals: if Mishka has more, she wins; if Chris has more, he wins; if they’re equal, it’s a draw, so print “Friendship is magic!^^”.
from collections import Counter
wins = Counter()
for _ in range(int(input())):
a, b = map(int, input().split())
if a > b:
wins['Mishka'] += 1
elif a < b:
wins['Chris'] += 1
if wins['Mishka'] > wins['Chris']:
print("Mishka")
elif wins['Chris'] > wins['Mishka']:
print("Chris")
else:
print("Friendship is magic!^^")
B. Kassu and a Beautiful Array
What is the only way to change the parity of a number?
To build a beautiful array b (all elements positive and of the same parity), we consider two cases:
- Case 1: All elements in a have the same parity Simply set bi = ai for all i
All elements in b will have the same parity →
YES - Case 2: Mixed parities (some even, some odd)
- We cannot make all numbers even, because to change an odd to even, we must subtract another odd but subtracting from the smallest odd number would make it zero or negative, which is invalid.
- We can try to make all numbers odd by subtracting an odd number from an even (since even − odd = odd). This is valid only if the smallest number in the array is odd, so we can subtract it from all even numbers without making results non-positive.
- If all numbers have the same parity →
YES - Else, if the minimum number is odd → we can make all elements odd →
YES - Else →
NO Time Complexity:
O(N) per test caset = int(input())
for _ in range(t):
n = int(input())
a = list(map(int, input().split()))
has_odd = any(x % 2 == 1 for x in a)
has_even = any(x % 2 == 0 for x in a)
if not (has_odd and has_even):
print("YES")
else:
if min(a) % 2 == 1:
print("YES")
else:
print("NO")
C. The Hidden Permutation
The graph is constructed from a hidden permutation p such that an undirected edge exists between p[i] and p[j] if and only if i < j and p[i] < p[j]. This means each node is connected to the nodes that come after it in the permutation and are larger in value. To reconstruct the permutation, we observe that a node with no unchosen neighbors smaller than itself must appear last among the remaining elements. So we iteratively pick the largest unchosen node that has no unchosen neighbors with smaller values—ensuring the relative order constraints are respected.
By maintaining the count of unchosen smaller neighbors for each node, and updating it as nodes are selected, we can efficiently reconstruct the permutation in reverse. The final result is the correct permutation.
from collections import defaultdict
def solve():
n = int(input())
adj = defaultdict(set)
for r_zeroidx in range(n): # r_zeroidx from 0 to n-1
row_str = input()
for c_zeroidx in range(n): # c_zeroidx from 0 to n-1
if row_str[c_zeroidx] == '1':
# Convert 0-indexed matrix coordinates to 1-indexed node IDs
node_u = r_zeroidx + 1
node_v = c_zeroidx + 1
# Add edges for an undirected graph
adj[node_u].add(node_v)
adj[node_v].add(node_u)
# small_degree[i] will store the count of neighbors 'j' of node 'i'
# such that 'j < i' AND 'j' is currently unchosen.
# Initially, all nodes are unchosen, so we count all neighbors 'j' with 'j < i'.
small_degree = [0] * (n + 1) # Using 1-based indexing, so index 0 is unused
for i in range(1, n + 1):
for neighbor_node in adj[i]:
if neighbor_node < i:
small_degree[i] += 1
ans = []
is_chosen = [False] * (n + 1) # Using 1-based indexing
# We need to select n nodes for the permutation
for _ in range(n):
chosen_node_this_iteration = -1
# Find the largest unchosen node 'c' such that small_degree[c] == 0.
# This means 'c' has no unchosen neighbors smaller than itself.
for node_val in range(n, 0, -1): # Iterate from n down to 1
if not is_chosen[node_val] and small_degree[node_val] == 0:
chosen_node_this_iteration = node_val
break
# According to the problem's constraints and logic,
# a suitable node should always be found in each step.
# If chosen_node_this_iteration remained -1, it would imply an issue.
ans.append(chosen_node_this_iteration)
is_chosen[chosen_node_this_iteration] = True
# Now, update the small_degree counts for the neighbors of the chosen_node.
# When chosen_node_this_iteration (let's call it X) is picked:
# Consider an unchosen neighbor V of X.
# If X < V, then X was a "small neighbor" for V. Since X is now chosen,
# it no longer contributes to V's small_degree.
for neighbor in adj[chosen_node_this_iteration]:
if not is_chosen[neighbor]: # Only affect unchosen neighbors
if chosen_node_this_iteration < neighbor:
small_degree[neighbor] -= 1
print(*(ans))
if __name__ == '__main__':
t = int(input())
for _ in range(t):
solve()
D. Tomas and Binary String
You're trying to maximize the XOR between two substrings.
Try fixing one of them — particularly a suffix starting from the first '0' in the string.
You're given a binary string s that starts with 1. You need to pick two non-empty substrings (they may overlap) and maximize their XOR value when interpreted as binary numbers.
Observations:
- Leading Substrings Have Higher MSB Weight
- Since XOR values are just number differences, longer prefixes/suffixes with higher bits turned on can lead to large XOR values.
- We Can Fix One Substring to Reduce Complexity
- Instead of checking all O(n²) substrings (too slow), we fix one of the substrings and slide a window across the string to find the other that gives maximum XOR.
We choose the suffix starting at the first '0' because:
- Any string starting with '1' will be numerically large.
- A suffix starting with the first '0' ensures we get a different structure from the prefix (increases XOR chance).
- Sliding Window + Bitmasking
- We fix the right substring: the suffix from the first
0to the end. - Convert it to a number:
suffix_val = int(s[first_zero_idx:], 2) Slide a window of the same length from the start of the string and keep the binary number in the window up to date using bit operations:
- Left shift to add a new bit.
- Mask to keep only the last
kbits.
- XOR the current window value with the fixed suffix value and track the maximum.
- Why This Works Efficiently
- Each test case is processed in linear time w.r.t the string length.
- Since total input length over all test cases is ≤ 5000, the solution runs in O(total_length) time.
Steps:
- For each test case:
- If the string contains only
1s, just return the full string and any single character (e.g.,1 1). Else:
- Fix the suffix starting from the first
0. - Slide a window of same length from the beginning of the string.
- Track the window with maximum XOR.
- Fix the suffix starting from the first
Example Walkthrough:
Input:
s = 1000
- Suffix:
000(starts from index 2), value = 0 - Try windows of length 3:
100→ 4 ⊕ 0 = 4000→ 0 ⊕ 0 = 0 → Best XOR = 4 → return(1, 3)and(1, 4)
Complexity:
- Per test case: O(n)
- Total: O(5000)
t = int(input())
for _ in range(t):
s = input()
first_zero_idx = s.find('0')
if first_zero_idx == -1:
print(1, len(s), 1, 1)
else:
window_len = len(s) - first_zero_idx
window_mask = (1 << window_len) - 1
msb_mask = 1 << (window_len - 1)
fixed_suffix_numeric_val = int(s[first_zero_idx:], 2)
current_window_numeric_val = int(s[:window_len], 2)
max_xor_val = current_window_numeric_val ^ fixed_suffix_numeric_val
best_window_indices = [0, window_len - 1]
for window_end_idx in range(window_len, len(s)):
current_window_numeric_val <<= 1
current_window_numeric_val &= window_mask
if s[window_end_idx] == '1':
current_window_numeric_val |= 1
current_xor_result = current_window_numeric_val ^ fixed_suffix_numeric_val
if current_xor_result > max_xor_val and (current_window_numeric_val & msb_mask):
max_xor_val = current_xor_result
window_start_idx = window_end_idx - window_len + 1
best_window_indices = [window_start_idx, window_end_idx]
print(1, len(s), best_window_indices[0] + 1, best_window_indices[1] + 1)
E. Bitwise OR and Spanning Trees
To minimize a bitwise OR sum, you want as many bits as possible to be 0, especially the most significant ones. Consider processing the bits from most significant to least significant. For each bit, decide if it must be set in the final answer to maintain connectivity.
The problem asks us to find a spanning tree of a given connected weighted undirected graph such that the bitwise OR of the edge weights (referred to as "ority") is minimized.
Observations:
Bitwise OR Property: If any edge in the chosen spanning tree has a specific bit set to 1, that bit will also be 1 in the final "ority" sum. To minimize the ority, we prioritize keeping higher (more significant) bits as 0.
Greedy Approach by Bit: This suggests a greedy strategy: determine the bits of the minimum ority from MSB down to LSB. For each bit, we try to keep it 0, only setting it to 1 if necessary to maintain connectivity.
Strategy: Iterating Through Bits
Initialize min_ority_so_far = 0 and vis (a boolean array for edges, initially all 0s, where vis[j]=1 means edge j is "banned" because using it would force a higher bit to become 1). Iterate from bit 29 down to 0:
For each bit b:
Hypothesis: Tentatively assume the $$$b$$$-th bit of
min_ority_so_farcan be 0, consistent with higher bits already determined.Candidate Edges: Create a new DSU structure. Consider only edges $$$(u, v, w)$$$ where:
- The $$$b$$$-th bit of $$$w$$$ is 0.
- The edge is not "banned" by previous decisions (i.e.,
vis[j] == 0). - Edges that have their $$$b$$$-th bit set, or are already banned, are temporarily stored in a
templist.
Connectivity Check: Use DSU to check if all $$$N$$$ vertices can be connected using only these candidate edges.
Decision for Bit
b:- If Connected: All vertices can be connected using only edges that keep bit $$$b$$$ as 0.
- The $$$b$$$-th bit of
min_ority_so_farremains 0. - Crucially: Mark all edges in
temp(those that had their $$$b$$$-th bit set but were not yet banned) asvis[j] = 1. This bans them because using them would unnecessarily set bit $$$b$$$ to 1.
- The $$$b$$$-th bit of
- If Not Connected: We must use at least one edge with the $$$b$$$-th bit set to form a spanning tree.
- The $$$b$$$-th bit of
min_ority_so_farmust be 1. Update:min_ority_so_far = min_ority_so_far | (1 << b). - Edges from
tempthat were active and had their $$$b$$$-th bit set are not banned by this step, as they are now consistent withmin_ority_so_farhaving bitbset.
- The $$$b$$$-th bit of
- If Connected: All vertices can be connected using only edges that keep bit $$$b$$$ as 0.
After iterating through all bits, min_ority_so_far holds the minimum possible ority.
Complexity:
- Outer loop:
bliterations (approximately 30 for typical integer sizes). - Inner loop (per bit):
- DSU initialization: $$$\mathcal{O}(N)$$$.
- Iterating through $$$M$$$ edges: $$$\mathcal{O}(M \cdot \alpha(N))$$$, where $$$\alpha(N)$$$ is the inverse Ackermann function (which is practically constant).
- Total Complexity: $$$\mathcal{O}(\text{bl} \cdot (N + M \cdot \alpha(N)))$$$. This approach is efficient for the given constraints.
import sys
class dsu:
def __init__(self, size):
self.parent = [i for i in range(size + 1)]
self.size = [1 for i in range(size + 1)]
def find(self, x):
while x != self.parent[x]:
self.parent[x] = self.parent[self.parent[x]]
x = self.parent[x]
return x
def union(self, x, y):
px = self.find(x)
py = self.find(y)
if px != py:
if self.size[px] > self.size[py]: # Union by size
px, py = py, px
self.parent[px] = py
self.size[py] += self.size[px]
def solve():
s = sys.stdin.readline().strip().split() # empty line
n, m = list(map(int, sys.stdin.readline().strip().split()))
edges = []
bl = 30
for _ in range(m):
edges.append(tuple(map(int, sys.stdin.readline().strip().split())))
ans = 0
vis = [0] * (m + 1) # vis[j]=1 if edge j is "banned"
for i in range(bl - 1, -1, -1): # Iterate from MSB downwards
graph = dsu(n)
temp = [] # Stores indices of edges that have the i-th bit set AND are not yet banned
for j in range(m):
u_node, v_node, w_val = edges[j]
# If (bit_i is 0 AND edge_j is active), add to DSU
# Else (bit_i is 1 OR edge_j is banned), add edge_j_index to temp
if (w_val >> i) & 1 == 0 and vis[j] == 0:
graph.union(u_node, v_node)
else:
temp.append(j)
# Check connectivity: can we connect the graph using only edges with i-th bit = 0?
can_connect_without_setting_bit_i = False
if n == 0: # Problem constraints n >= 3, so this case is mostly theoretical
can_connect_without_setting_bit_i = True
elif n > 0 and graph.size[graph.find(1)] == n :
can_connect_without_setting_bit_i = True
if can_connect_without_setting_bit_i:
# Yes, we can connect without setting the i-th bit.
# The i-th bit of 'ans' remains 0.
# Ban all edges in 'temp' that were active and would set bit i.
for val_idx in temp:
vis[val_idx] = 1
else:
# No, we must use an edge that sets the i-th bit.
# The i-th bit of 'ans' must be 1.
ans += (1 << i)
# Edges in 'temp' that were active and set bit i are NOT banned,
# as they are now consistent with 'ans' having bit 'i' set.
print(ans)
q = int(sys.stdin.readline().strip())
for _ in range(q):
solve()







