Here is the link to the contest. All problems are from Codeforces' problem set
To determine whether a melody is perfect, we check each pair of consecutive notes in the sequence. For each pair $$$a_i, a_{i+1}$$$, we calculate the interval as $$$|a_i - a_{i+1}|$$$. We then verify whether this interval is one of the allowed values, 5 or 7. If all consecutive intervals satisfy this condition, the melody is perfect and the answer is "YES". Otherwise, if any interval is not 5 or 7, the melody is not perfect and the answer is "NO".
This method ensures that every adjacent pair is validated exactly once, giving a time complexity of $$$O(n)$$$ and a space complexity of $$$O(1)$$$.
n = int(input())
notes = list(map(int, input().split()))
perfect = True
for i in range(n - 1):
interval = abs(notes[i] - notes[i + 1])
if interval not in (5, 7):
perfect = False
break
print("YES" if perfect else "NO")
Operation:
- Pick $$$\min(a)$$$ and $$$\max(b)$$$.
- Swap if $$$\min(a) \lt \max(b)$$$.
Repeat:
- Perform up to $$$k$$$ times or until no improvement is possible.
Idea:
- Each swap increases the sum of $$$a$$$ (or decreases $$$b$$$) toward the objective.
- Always choose the best candidates (greedy strategy).
Complexity:
- Naive: $$$O(n \cdot k)$$$ → can be $$$O(n^3)$$$
- Optimized: Sort arrays, use pointers → $$$O(n \log n)$$$
test = int(input())
for _ in range(test):
n, k = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
a.sort()
b.sort(reverse=True)
for i in range(min(k, n)):
if a[i] < b[i]:
a[i], b[i] = b[i], a[i]
else:
break
print(sum(a))
We are given:
An integer $$$n$$$ (divisible by $$$3$$$).
An array $$$a_1, a_2, \dots, a_n$$$.
In one move, we can pick an index $$$i$$$ $$$(1 \le i \le n)$$$ and replace $$$a_i$$$ with $$$a_i + 1$$$.
We define:
$$$c_0$$$ = number of elements where $$$a_i \bmod 3 = 0$$$
$$$c_1$$$ = number of elements where $$$a_i \bmod 3 = 1$$$
$$$c_2$$$ = number of elements where $$$a_i \bmod 3 = 2$$$
The array is balanced if: $$$c_0 = c_1 = c_2$$$
Our task: Find the minimum number of moves to make the array balanced.
Key Observations
Target count for each group:
Since $$$n$$$ is divisible by 3, the balanced state means: $$$\text{target} = \frac{n}{3}$$$
Allowed move effect:
If $$$a_i \bmod 3 = 0$$$, one increment moves it to remainder $$$1$$$.
If $$$a_i \bmod 3 = 1$$$, one increment moves it to remainder $$$2$$$.
If $$$a_i \bmod 3 = 2$$$, one increment moves it to remainder $$$0$$$.
This forms a cycle:$$$0 \to 1 \to 2 \to 0$$$
Excess and deficit handling:
If $$$c_k \gt \text{target}$$$ for some $$$k$$$, we can move the excess elements to the next group $$$(k+1) \bmod 3$$$.
Each such move costs 1 increment per element shifted.
Balancing Process
Count $$$c_0$$$, $$$c_1$$$, $$$c_2$$$.
While not all equal to
target:For $$$i \in {0,1,2}$$$:
- If $$$c_i \gt \text{target}$$$:
- $$$\text{excess} = c_i - \text{target}$$$
- Transfer $$$\text{excess}$$$ elements to group $$$(i+1) \bmod 3$$$
- Increase move counter by $$$\text{excess}$$$
- If $$$c_i \gt \text{target}$$$:
Stop when:$$$c_0 = c_1 = c_2 = \text{target}$$$
Example Walkthrough
Example:
$$$n = 6$$$, $$$a = [0, 2, 5, 5, 4, 8]$$$
- Initial remainders:
- Target: $$$\frac{6}{3} = 2$$$
Step 1: $$$c_2$$$ has excess $$$2$$$. Move them to $$$c_0$$$:
Step 2: $$$c_0$$$ has excess $$$1$$$. Move it to $$$c_1$$$:
Balanced in 3 moves.
test = int(input())
for _ in range(test):
n = int(input())
arr = list(map(int, input().split()))
# Count remainders
cnt = [0, 0, 0]
for x in arr:
cnt[x % 3] += 1
target = n // 3
moves = 0
# Keep balancing
while cnt[0] != target or cnt[1] != target or cnt[2] != target:
for i in range(3):
if cnt[i] > target:
excess = cnt[i] - target
cnt[i] -= excess
cnt[(i + 1) % 3] += excess
moves += excess
print(moves)
We are given $$$n$$$ days of vacation.
For each day, Vasya knows:
- Whether the gym is open.
- Whether there is a contest.
On each day, Vasya can:
- Rest
- Write the contest (if available)
- Go to the gym (if open)
Constraint:
He cannot do the same activity (contest or gym) on two consecutive days.
Goal:
Minimize the number of rest days.
Observation
This is a Dynamic Programming (DP) problem because:
The decision for day $$$i$$$ depends on what was done on day $$$i-1$$$.
There’s a constraint to avoid repeating the same activity consecutively.
State Definition
Let:
- $$$dp[i][0]$$$ → Minimum rest days till day $$$i$$$ if Vasya rests on day $$$i$$$.
- $$$dp[i][1]$$$ → Minimum rest days till day $$$i$$$ if Vasya participates in a contest on day $$$i$$$.
- $$$dp[i][2]$$$ → Minimum rest days till day $$$i$$$ if Vasya goes to the gym on day $$$i$$$.
Transition
1. Rest Case
If Vasya rests on day $$$i$$$:
- $$$dp[i][0] = 1 + \min(dp[i-1][0],\ dp[i-1][1],\ dp[i-1][2])$$$
- Because resting adds 1 rest day to the minimum of all possible previous states.
2. Contest Case
If there is a contest on day $$$i$$$ and he didn't do a contest yesterday:
- $$$dp[i][1] = \min(dp[i-1][0],\ dp[i-1][2])$$$
- We take the minimum rest days from rest yesterday or gym yesterday.
- If no contest is available, $$$dp[i][1]$$$ is infinite (or invalid).
3. Gym Case
If the gym is open on day $$$i$$$ and he didn’t go to the gym yesterday:
- $$$dp[i][2] = \min(dp[i-1][0],\ dp[i-1][1])$$$
- We take the minimum rest days from rest yesterday or contest yesterday.
- If the gym is closed, $$$dp[i][2]$$$ is infinite (or invalid).
Initialization
For day $$$1$$$:
- If rest: $$$dp[1][0] = 1$$$
- If contest possible: $$$dp[1][1] = 0$$$
- If gym possible: $$$dp[1][2] = 0$$$
- If both possible: choose based on availability.
Answer
The final answer is:$$$\min(dp[n][0],\ dp[n][1],\ dp[n][2])$$$
This gives the minimum number of rest days possible after $$$n$$$ days.
def solve():
n = int(input().strip())
days = list(map(int, input().strip().split()))
INF = float('inf')
# dp[i][0] → rest day
# dp[i][1] → contest day
# dp[i][2] → gym day
dp = [[INF] * 3 for _ in range(n + 1)]
# Base case (day 0 — no days taken yet)
dp[0][0] = dp[0][1] = dp[0][2] = 0
for i in range(1, n + 1):
activity = days[i - 1]
# rest day
dp[i][0] = 1 + min(dp[i - 1])
if activity in (1, 3):
dp[i][1] = min(dp[i - 1][0], dp[i - 1][2])
# didn't do gym yesterday
if activity in (2, 3):
dp[i][2] = min(dp[i - 1][0], dp[i - 1][1])
print(min(dp[n]))
solve()
You are given an array $$$a = [a_1, a_2, \dots, a_n]$$$. In one operation, you can choose two distinct elements $$$a_i$$$ and $$$a_j$$$ ($$$i \neq j$$$) and decrease each of them by 1.
You need to determine whether it is possible to reduce all elements to zero.
Step 1: Understanding the Operation
Each operation reduces the sum of all elements by 2: $$$\text{new sum} = \text{old sum} - 2$$$
Therefore, if the sum of all elements is initially odd, we can never reach zero because subtracting 2 repeatedly will always leave an odd number.
Condition 1: $$$\sum_{i=1}^{n} a_i$$$ must be even.
Step 2: Considering the Largest Element
Let $$$M = \max(a_1, a_2, \dots, a_n)$$$ and $$$S_{\text{rest}} = \sum_{i=1}^{n} a_i - M$$$
- To reduce $$$M$$$ to zero, we need to pair it with other elements in each operation.
- If $$$M \gt S_{\text{rest}}$$$, there aren’t enough elements to pair with $$$M$$$ to bring it down to zero.
Condition 2: $$$M \le S_{\text{rest}} = \sum_{i=1}^{n} a_i - M$$$
Step 3: Proof of Sufficiency
If both conditions hold:
- $$$\sum_{i=1}^{n} a_i$$$ is even.
- $$$M \le \sum_{i=1}^{n} a_i - M$$$
Then we can always reduce all elements to zero using a greedy pairing strategy:
- Always pair the two largest remaining elements.
- Each operation decreases the sum by 2.
- Because the total sum is even, we can eventually reach a sum of zero.
- The largest element $$$M$$$ can always find a partner (since $$$M \le S_{\text{rest}}$$$).
This proves that both conditions are sufficient.
Step 4: Algorithm
Compute the sum of all elements:$$$\text{sum_a} = \sum_{i=1}^{n} a_i$$$
Find the maximum element: $$$M = \max(a_1, a_2, \dots, a_n)$$$
Check the two conditions: $$$\sum_{i=1}^{n} a_i \equiv 0 \pmod{2} \quad \text{and} \quad M \le \sum_{i=1}^{n} a_i - M$$$
- If both are true →
"YES" - Otherwise →
"NO"
- If both are true →
Step 5: Examples
Example 1:[0, 0, 2, 2]
- Sum: $$$\sum a_i = 1+1+2+2 = 6 \quad \text{(even)}$$$
- Maximum element:$$$M = 2$$$
Sum of others:$$$S_{\text{rest}} = 6 - 2 = 4 \quad (\text{and } M \le S_{\text{rest}})$$$
Both conditions satisfied → YES
Operations:
- Decrease $$$a_1$$$ and $$$a_2$$$:
[0,0,2,2] - Decrease $$$a_3$$$ and $$$a_4$$$:
[0,0,1,1] - Decrease $$$a_3$$$ and $$$a_4$$$:
[0,0,0,0]
- Decrease $$$a_1$$$ and $$$a_2$$$:
Example 2:[1, 2, 3, 4, 5, 6]
- Sum: $$$\sum a_i = 1+2+3+4+5+6 = 21 \quad \text{(odd)} $$$
- Sum is odd → NO
- Even if the sum were even, check $$$M$$$: $$$M = 6, \quad S_{\text{rest}} = 15 \quad (M \le S_{\text{rest}}) $$$
Condition 1 fails → impossible to reach zero.
def solve(arr):
total_sum = sum(arr)
max_elem = max(arr)
# First Condition
if total_sum % 2 != 0:
return "NO"
# Second Condition
if max_elem > total_sum - max_elem:
return "NO"
return "YES"
n = int(input())
arr = list(map(int, input().split()))
print(solve(arr))
If you are not interested in competitive programming, this problem is not interview-friendly. You don’t have to solve or understand it, but if you do, it will be a plus for your problem-solving skills
Euler Tour Technique (ETT)
The Euler Tour Technique (ETT) is a method used in tree algorithms to efficiently answer queries on trees, particularly for subtree queries, path queries, and Lowest Common Ancestor (LCA) problems.
1. What is an Euler Tour?
An Euler Tour of a tree is a traversal that:
- Starts at the root.
- Visits every edge exactly twice (once entering a node, once leaving it).
- Produces a linear representation of the tree.
This linear representation allows us to use array-based data structures like segment trees or Fenwick trees for efficient queries.
2. Tree Example
Consider the following tree:
[1]
/ | \
[2] [3][4]
/ \
[5] [6]
3. Euler Tour (Full)
The full Euler Tour of the above tree (recording nodes on both entry and exit) is:[1, 2, 5, 5, 6, 6, 2, 3, 3, 4, 4, 1]
Each node appears twice (except leaves, which appear consecutively).
This sequence represents the entry and exit times of nodes.
Subtree queries can now be treated as contiguous segments in this array.
4. Entry and Exit Times
- Entry time (in-time): When DFS enters a node.
- Exit time (out-time): When DFS exits a node.
Using the Euler Tour array, you can define subtrees:
- Subtree of node 2:
[2, 5, 5, 6, 6, 2] - Subtree of node 3:
[3, 3]
This allows subtree queries to be reduced to simple range queries.
5. Key Concepts
- Flattening the tree: Transforming the tree structure into a linear array.
- Subtree queries: Can be reduced to range queries on the array.
- LCA computation: Combine Euler Tour with Range Minimum Query (RMQ).
- Dynamic programming on trees: Enables efficient subtree updates and queries.
6. Types of Euler Tours
- Full Euler Tour (Nodes)
Description
- Visits each node twice: on entry and on exit.
- Generates a linear array where each node appears multiple times.
- Useful for subtree queries and segment tree/Fenwick tree applications.
Steps
- Start DFS from the root node.
- When entering a node, record it in the Euler Tour array.
- Recursively visit all children.
- When leaving the node, record it again in the array.
- Maintain entry and exit times for each node.
- First Occurrence Euler Tour (Nodes)
Description
- Records each node only the first time it is visited during DFS.
- Mostly used for Lowest Common Ancestor (LCA) queries.
- Reduces the array size compared to Full Euler Tour.
Steps
- Start DFS from the root.
- When entering a node for the first time, record it in the array.
- Recursively visit all children, recording the node only on first visit.
- Keep track of first occurrence index of each node in the array.
- Euler Tour of Edges
Description
- Focuses on edges instead of nodes.
- Each edge is visited exactly twice: when going down and when going up.
- Useful for edge-related queries, e.g., finding sum of weights in a subtree or path.
Steps
- Start DFS from the root.
- When moving from parent → child, record the edge.
- Recursively visit children.
- When returning from child → parent, record the edge again.
- Use this array to handle edge-based queries efficiently.
Summary of Differences
| Type | Node Visits | Array Size | Common Use Case |
|---|---|---|---|
| Full Euler Tour (Nodes) | Entry & Exit | 2n-1 | Subtree queries, segment trees |
| First Occurrence Euler Tour | First Visit Only | n | LCA computation using RMQ |
| Euler Tour of Edges | Each edge twice | 2(n-1) | Edge-related queries, path sums |
---
7. Applications
- Subtree sum/min/max queries using segment trees or Fenwick trees.
- Lowest Common Ancestor (LCA) queries with RMQ.
- Path queries by transforming them into range queries.
- Dynamic programming on trees for efficient updates and queries.
8. Resources for Further Reading
- USACO Guide
- CP-Algorithms: Euler Tour Technique
- GeeksforGeeks: Euler Tour in Trees
- TopCoder Tutorial on LCA and Euler Tour
Summary:
Euler Tour Technique linearizes a tree, enabling efficient subtree and path queries, LCA computation, and tree DP operations. It relies on recording nodes at entry and exit times to flatten the tree into an array like:
Segment Tree
A Segment Tree is a binary tree data structure used to efficiently perform range queries and point or range updates on an array. It is extremely useful when you need fast queries on subarrays, such as sum, minimum, maximum, greatest common divisor (GCD), etc.
1. Concept
Suppose you have an array
arrof sizen.You want to answer queries like:
- Sum of elements from index
ltor
- Minimum element from index
ltor
- Maximum element from index
ltor
- Count of elements satisfying a property in a range
- Sum of elements from index
Naive approach: Iterate through the range → O(n) per query
- Segment Tree approach: Preprocess in O(n) or O(n log n) → Answer queries in O(log n)
How It Works
Divide and Conquer:
- Divide the array into two halves recursively until each segment contains one element (leaf node).
- Each internal node stores the aggregate information (sum, min, max, etc.) of its children.
Binary Tree Representation:
- Root represents the whole array.
- Leaf nodes represent individual array elements.
- Internal nodes represent ranges combining the information of their children.
2. Structure
- For an array of size `n`, the segment tree requires **approximately 2*n nodes** (or next power of 2). - Each node stores the **result of the segment** it represents.
Segment Tree Example (Sum)
Array: [1, 3, 5, 7, 9, 7,11, 11]
Segment Tree (Sum):
[54]
/ \
[16] [38]
/ \ / \
[4] [12] [16] [22]
/ \ / \ / \ / \
[1] [3] [5] [7][9] [7][11][11]
Root
[54]= sum of all elements.Left child
[16]= sum of[1,3,5, 7]Leaf nodes = individual elements.
3. Operations
3.1 Query
- Purpose: Answer range queries (sum, min, max, etc.).
- Method: Start from the root. If the current segment is completely within the query range, use it. If partially overlapping, query left and right children recursively.
- Time Complexity: O(log n)
3.2 Update
- Point Update: Update a single element and propagate changes up the tree.
- Range Update: Advanced Segment Trees with lazy propagation can handle efficient range updates.
- Time Complexity: O(log n)
4. Variants
- Min/Max Segment Tree: Stores minimum/maximum of a range.
- Sum Segment Tree: Stores sum of elements in a range.
- GCD Segment Tree: Stores greatest common divisor of a range.
- Lazy Segment Tree: Supports efficient range updates using lazy propagation.
- 2D Segment Tree: For queries on a 2D matrix.
5. Applications
- Range sum, minimum, maximum queries
- Frequency/count of elements in a range
- Finding first/last element satisfying a condition in a range
- Competitive programming problems (queries and updates in arrays)
- Integration with Euler Tour Technique to handle subtree queries in trees efficiently
6. Advantages
- Handles dynamic queries and updates efficiently
- O(log n) query and update time
- Works for multiple types of aggregation functions
- Can be combined with other techniques like Euler Tour for tree problems
7. Resources for Further Reading
- CP-Algorithms: Segment Tree
- GeeksforGeeks: Segment Tree
- TopCoder Tutorial: Segment Tree
- Codeforces EDU: Segment Tree
Summary:
Segment Tree is a powerful binary tree data structure that enables fast range queries and updates. It is especially useful in competitive programming and algorithms where the array changes dynamically or multiple queries need to be answered efficiently.
Even if the approach is optimal, it is not accepted by Codeforces.
- You can either change the code to C++ or Java
- Or just understand it and analyze its time complexity
Note: I will update it as soon as I find a more optimal solution than this one.
The key idea is to flatten the tree into an array so that every subtree becomes a contiguous segment.
We run a DFS from the root 1 and record:
- Entry time
tin[v]when a vertexvis first visited - Exit time
tout[v]after all its descendants are processed
If t is a global time incremented on entry, we define an order array ord[t] such thatord[tin[v]] = v.
It is standard that the subtree of v corresponds exactly to the segment[tin[v], tout[v]] in this DFS order (Euler tour).
Hence, every query “on the subtree of v” reduces to a range operation on [tin[v], tout[v]].
Color Representation as Bitmask
Each vertex color c ∈ {1, …, 60} is represented as a bitmask in a 64-bit integer:
mask(c) = 1 << (c - 1)
For the flattened array A of length n:
A[i] = mask(c_ord[i])
A segment’s set of colors is then the bitwise OR of its elements.
If a segment covers colors S, its mask is:
mask(S) = OR_{x ∈ S} mask(x)
The number of distinct colors is:
#colors = popcount(mask(S))
Segment Tree with Lazy Propagation
We build a segment tree over A with lazy propagation.
For each node x in the tree:
M_x= bitwise OR of allA[i]foriin this node's segmentL_x= lazy tag, initially unset (e.g.,-1), meaning “no pending assignment.”
If set, it holds a uniform mask meaning “paint this entire segment with this mask.”
Operations
1) Range Paint (Type 1)
Painting all vertices in the subtree of v with color c means assigning:
V = mask(c)
to the segment [tin[v], tout[v]].
For a fully covered segment:
- Set
M_x = V - Set
L_x = V
For partial overlap:
- Push
L_xdown to children if needed - Recurse into children
2) Range Query (Type 2)
Counting distinct colors in the subtree of v means:
Ans(v) = popcount(OR_query([tin[v], tout[v]]))
The segment tree merges results by bitwise OR:
res = M_left | M_right
Correctness
We maintain two invariants:
- If
L_xis unset, thenM_xis the OR of the actual values in the segment. - If
L_xis set, then the entire segment is painted with that mask.
Updates replace segments with a constant mask. Push operations ensure children remain consistent.
Because bitwise OR matches set union on these masks, the query result is correct,
and popcount returns the correct count of distinct colors.
Complexity
- Preprocessing (DFS):
O(n) - Range Paint:
O(log n) - Range Query:
O(log n)
Total time: O((n + m) log n)
Space: O(n) for the tree and segment tree.
Summary:
- Flatten the tree via DFS (
tin,tout). - Store colors as 64-bit masks.
- Maintain a segment tree with lazy range assignment and range OR queries.
- Answer queries with
popcountof the returned mask.
import sys
sys.setrecursionlimit(1 << 25)
input = sys.stdin.readline
n, m = map(int, input().split())
colors = list(map(int, input().split()))
adj = [[] for _ in range(n + 1)]
for _ in range(n - 1):
u, v = map(int, input().split())
adj[u].append(v)
adj[v].append(u)
# Euler Tour Flattening
tin = [0] * (n + 1)
tout = [0] * (n + 1)
order = [0] * (n + 1)
timer = 0
def dfs(u, p):
global timer
timer += 1
tin[u] = timer
order[timer] = u
for v in adj[u]:
if v != p:
dfs(v, u)
tout[u] = timer
dfs(1, -1)
size = 1
while size < n:
size <<= 1
tree = [0] * (2 * size)
lazy = [-1] * (2 * size)
def build():
for i in range(1, n + 1):
node = order[i]
tree[size + i - 1] = 1 << (colors[node - 1] - 1)
for i in range(size - 1, 0, -1):
tree[i] = tree[i * 2] | tree[i * 2 + 1]
def apply(node, value):
tree[node] = value
lazy[node] = value
def push(node):
if lazy[node] != -1:
apply(node * 2, lazy[node])
apply(node * 2 + 1, lazy[node])
lazy[node] = -1
def update(l, r, value, node=1, lx=1, rx=size):
if r < lx or rx < l:
return
if l <= lx and rx <= r:
apply(node, value)
return
push(node)
mid = (lx + rx) // 2
update(l, r, value, node * 2, lx, mid)
update(l, r, value, node * 2 + 1, mid + 1, rx)
tree[node] = tree[node * 2] | tree[node * 2 + 1]
def query(l, r, node=1, lx=1, rx=size):
if r < lx or rx < l:
return 0
if l <= lx and rx <= r:
return tree[node]
push(node)
mid = (lx + rx) // 2
return query(l, r, node * 2, lx, mid) | query(l, r, node * 2 + 1, mid + 1, rx)
build()
for _ in range(m):
q = list(map(int, input().split()))
if q[0] == 1:
v, c = q[1], q[2]
update(tin[v], tout[v], 1 << (c - 1))
else:
v = q[1]
res = query(tin[v], tout[v])
print(res.bit_count()) # Python 3.10+








