International Collegiate Programming Contest (ICPC)
2024 Asia Dhaka Regional Contest
Onsite Round - Editorial
Hosted By
Department of Computer Science and Engineering
Daffodil International University
Supported by
ICPC Dhaka Regional Contest, 2024 Editorial
Hosted By: Daffodil International University
Problem A. Are the Nodes Reachable?
Problem Setter: Raihat Zaman Neloy
Tester: Rumman Mahmud, Pritom Kundu, Nafis Sadique
Category: Ad-hoc
Total Solved: 0
First to Solve: N/A
We can split the problem into two subproblems.
When ans < 32. How do we solve it? First for each vertex calculate the list of vertex reachable from it.
Also calculate the list of vertex from which it is reachable. Both can be done in O( max(n)·m64 ) using bitsets.
Now assume that vertex a is reachable from vertex b. In that case vertices b − 1 or b + 1 will be reachable by
adding an edge of cost 1. We can find all the vertices from which vertex a is reachable with 1 cost by simply
binary shifting the bitset by 1 in both direction and apply the bitwise OR operator on all three (no change,
left shift, right shift). If we do this again then we find the vertices 2 distance away and so on. We keep doing
2
this for distances upto 31. The complexity to do this is O( n 64·32 ).
Now, lets split the bitsets into 64 sized buckets. Technically we could’ve used an unsigned long long ar-
ray to perform the bitset operations in the first place. For each vertex we will have 33 bitset buckets. 32 of
them are for the shifted bitsets from upstream and one for the downstream. Then for the query, we check if
the first upstream bucket of V with 31 shift and the downstream bucket of U has any match. We can do that
by simply performing a bitwise AND operation. If there is a match then we check 30 shift and keep reducing
n
it. If no match is found then we move to the next bucket. At the end in this approach we will need O( 64 + 32)
operations per query.
When ans ≥ 32. We again keep a bucket of vertices reachable from a vertex. Vertices numbered from
[1..64] are in one bucket, [65..128] are in second buckets and so on. For each bucket we only keep the mini-
mum and maximum id of the vertex reachable from it. Similarly we do it for the upstream vertices. For a
query, we merge those two list of vertices (min and max of each bucket), sort them and find the smallest gap in
consecutive vertices (one must be upstream while the other must be downstream). This takes O( 2·n64 ) per query.
Alternatively, we can do the same using 128 bit integers. The performance is comparable.
Problem B. Yet Another Crossover Episode
Problem Setter: Shahjalal Shohag
Tester: Rumman Mahmud, Pritom Kundu, Jubayer Rahman, Nafis Sadique
Category: Dynamic Programming, Bit Manipulation
Total Solved: 7
First to Solve: MBSTU Novatos
We know that x&y ≤ min(x, y) and it looks like gcd(x, y) ≤ min(x, y).
So, it looks like gcd(x ⊕ y, x&y) ≤ min(x ⊕ y, x&y) ≤ min(x, y).
Also notice that i can be equal to j, so it looks like the answer is max(a1 , a2 , . . . , an ) because this is the
maximum possible gcd.
But this is wrong due to the case when x = 0 or y = 0 because then gcd(x, y) = x when y = 0 and gcd(x, y) = y
when x = 0.
So, when ai ⊕ aj = 0, we have ai = aj , so gcd(ai ⊕ aj , ai &aj ) = gcd(0, ai &ai ) = gcd(0, ai ) = ai . So, for this
1
ICPC Dhaka Regional Contest, 2024 Editorial
Hosted By: Daffodil International University
case we need to take care of the maximum number of the array only.
And when ai &aj = 0, we have ai ⊕ aj = ai + aj because there is no common bit in ai and aj so xor and addition
are the same in this case.
So we need to find the maximum ai + aj where ai &aj = 0. So let’s fix ai and then find the maximum aj such
that ai &aj = 0 which means we need to find the maximum aj such that aj is a submask of the flipped bits of
ai .
Finding the maximum submask of a mask that exists in the array is a standard problem that can be solved
using Sum Over Subsets (SOS) DP. We can also find the count of such submasks using the same DP.
So overall we need to consider the maximum element of the array and the maximum sum of two elements such
that there is no common bit between them.
Time Complexity: O(m · 2m ) where m is the number of bits in the maximum element of the array which is
bounded by 23.
Problem C. Cut the Stick, Share You Must
Problem Setter: Rumman Mahmud
Tester: Shahjalal Shohag, Pritom Kundu, Nafis Sadique
Category: Math, Number Theory
Total Solved: 15
First to Solve: IUT CocolaChampionBiscuit
Since n & k are large (1 ≤ k < n ≤ 106 ), we need to find an optimal solution. Here are some hints be-
fore we dive into the actual solution. Let’s define a function P (n, k) that returns the number of ways to split
n into k partitions where the GCD of the partitions is a prime number.
• Hint 1: How would you solve it if the GCD was 1 instead of a prime number?
• Hint 2: How does changing the GCD to a prime affect n?
• Hint 3: Define f (n, k) to return the number of ways to split n into k partitions where the GCD of the
partitions is 1. Define another function g(n, k, p) to return the number of ways to split n into k partitions
where the GCD of the partitions is exactly p (with p being prime). Can you draw a relation between
g(n, k, p) and f ( np , k)?
Solution
A valid split will have a prime GCD. Let’s say the GCD of a valid sequence is p. This means each partition
will be a multiple of p. If we divide each partition by p, the new sequence will have GCD 1. The GCD cannot
be greater than 1, as otherwise, the GCD of the original sequence cannot equal p. Using this observation,
g(n, k, p) = f ( np , k).
To compute P (n, k), sum over all prime factors of n:
X n
P (n, k) = f ,k
p
p∈U (n)
Here, U (n) is the set of unique prime factors of n. The remaining challenge is finding the number of ways to
split n into k partitions with a GCD of 1. The Möbius function and binomial coefficients can be used for this
computation. Details are left as an exercise.
2
ICPC Dhaka Regional Contest, 2024 Editorial
Hosted By: Daffodil International University
Complexity
• Precomputing unique prime factors of all numbers: O(N log N )
• Precomputing factorial and inverse factorials modulo M : O(N + log M )
• Complexity of finding valid partitions per test case: For each prime factor pi , finding splits
ω( n )
with GCD 1 has a complexity of O(2 pi ). Repeating this for all unique prime factors of n gives
n
P ω( )
O( p∈U (n) 2 p ), where ω(n) is the number of unique prime factors of n.
ω( n )
• Overall complexity: O(N log N + T ·
P
p∈U (n) 2
p )
The maximum number of unique primes is 7. For example, the product of the first 7 primes is 2·3·5·7·11·13·17 =
ω( n )
510510. Adding another prime would exceed N . Hence, the maximum value of p∈U (n) 2 p is 7 · 26 = 448.
P
Which means, per query you will need to perform 448 operations in the worst case. Which is good enough for
the TL.
Bonus
We can further reduce the complexity by only considering the divisors of n that have at most one square prime
factor. We need to modify the Mobius function a bit to achieve that. To not spoil the fun, I will keep it as an
exercise for you as well.
Problem D. CatGPT
Problem Setter: Anik Sarker, Rafid Bin Mostofa
Tester: Rumman Mahmud, Pritom Kundu, Nafis Sadique
Category: Graph, Offline Processing
Total Solved: 40
First to Solve: FaimDeSang
There can be only 26 clowders. We can use this information. First, lets process all the event in the as-
cending order of Ri . We then process the cats from left to right. After processing each cat we keep in memory
the most recent position we saw a cat of clowder Ci . Then we process the events ended at the current position.
Because we know the last position for the clowder, we know that event will merge clowders that have their
last position > Li . We keep the list of merged clowders for the event in memory as well.
For the queries, we also process them in the ascending order of yi . But this time we iterate over the events
from left to right. Since we know for an event, the clowders that will be merged, we can generate a list of
unordered (i, j) pairs that will be merged for an event. There can’t be more than 25·26
2 pairs. We keep track of
the last event they were merged, similar to the previous section. Finally for an event, we process the queries
that ended in that event. From the list of the last position of the pairs, we can have a graph of 26 vertices.
We merge vertices using union-find. Then we check the largest merged clowder and output their size.
Problem E: Quasi-binary Representations
Problem Setter: Pritom Kundu
Tester: Shahjalal Shohag, Jubayer Rahman, Nafis Sadique
Category: Dynamic Programming, Math
Total Solved: 5
First to Solve: DU Primordius
Suppose we have placed the first k digits. The number formed the digits by we have placed must be less than
or equal to the value formed by first k bits in the binary representation. Suppose, the difference is d. We need
3
ICPC Dhaka Regional Contest, 2024 Editorial
Hosted By: Daffodil International University
to make up this difference from the lower bits. The key observation is if d > k, then whatever digits we place
in the lower position, we cannot make the difference up.
This allows us to do a dp solution. Define dp[i][x] be the number of ways to place the remaining digits assuming
that we have placed the first i digits and have a difference of x so far. Then,
k
X
dp[i][x] = dp[i − 1][(x + d − ni )/2]
0≤d≤k
x+d≡ni (mod 2)
This solution is O(k 2 log n) solution which is not enough. In order to pass optimize transitions to O(1) using
prefix sums. Overall time will be O(k log n) per testcase.
Problem F: Flowers
Problem Setter: Hasinur Rahman
Tester: Nafis Sadique
Category: Hashing, Divide & Conquer
Total Solved: 0
First to Solve: N/A
To solve this problem, we need to express the shapes of the trees as a hash value. We need to design the hash
function so that it will remain consistent about the tree structure whether we calculate it from the whole flower
or while merging it.
About the hash function: We will calculate the hash of the structure depending on the LRU path-string
of the preorder traversal of a flower. Here, “L” = Left child traversal from parent, “R” = Right child traversal
from the parent, “U” = Getting back to the parent after visiting all its children. It will ensure a uniquely
shaped tree traversal. Note that, if you don’t include the “U”, it will not express a unique shape.
About the flower merging: Let’s say two flowers A, and B are getting merged. B will be the child of the
leftmost leftless node of A. First, we will divide the hash of A into two parts, LeftHash and RightHash and
we know the hash of the structure of A. Now, think about how to merge them to get the hash of the merged
structure.
About tracking Unique Shapes: For each tree, we need to maintain a set of hash values. While merging,
If there are two sets S1 and S2 , we need to merge them following the rule: Always merge the light set and the
heavy set. This will lead to better-amortized complexity.
Time complexity: O(N × lg N )
Memory complexity: O(N )
Problem G: Library Function vs Keyword
Problem Setter: Shahriar Manzur
Tester: Jubayer Rahman, Nafis Sadique, Rumman Mahmud
Category: Ad-hoc
Total Solved: 228
First to Solve: BRACU Crows
For strlen(line), we simply need to find the position of the first null(‘\0’) character. The number of characters
before that is the answer. If no null characters exist then the answer would be the string length.
For sizeof (line), count the number of null in the string. Then the answer is:
string length − number of null characters + 1.
4
ICPC Dhaka Regional Contest, 2024 Editorial
Hosted By: Daffodil International University
Problem H: Hand Cricket
Problem Setter: Kazi Md Irshad
Tester: Pritom Kundu, Jubayer Rahman, Nafis Sadique
Category: Data Structure, Math, Probability
Total Solved: 0
First to Solve: N/A
The strategies are in Nash equilibrium. Therefore, Alice cannot improve her strategy. She will have the
same expected points for any index. Let this expected value be X. Let p1 , p2 , . . . , pN be Bob’s strategy. Then
for all i:
Ai · (1 − pi ) = X
X
pi = 1 −
Ai
N
X X
1= (1 − )
Ai
i=1
As sum of pi is 1. Adding this equation over all i gives:
N −1
X = PN 1
i=1 Ai
PN
Which means for range [L, R] the answer is X = PR−L
R 1 Alice needs to increase X. Reducing 1
i=1 Ai will
i=L Ai
increase X. It can be proved that Alice always increments the smallest Ai . To implement this efficiently, we
will build a persistent segment tree on the array values. The j th root of the segment tree will account for array
elements in the range [1, j]. The tree maintains the following:
• The sum of all Ai values in the range.
• The sum of inverses of Ai in the range.
• The count of elements available in the range.
We will walk the segment tree from the root for the (L − 1)th element and the root of the Rth element. During
this traversal, we will maintain:
• How much of K is left.
• The value and count of the small numbers that have been incremented.
On a segment tree node we can check if the whole subtree can be incremented to its maximum in O(1) and
also get the sum of inverses in O(1) if K depletes.
The complexity is O(QlogN ). However we have allowed slower solutions like O(Qlog 2 N ) (using binary search
and persistent segment tree), and O(Qlog 3 N ) (using binary search and merge sort tree).
5
ICPC Dhaka Regional Contest, 2024 Editorial
Hosted By: Daffodil International University
Problem I: In Search of a Kind Person
Problem Setter: Md. Imran Bin Azad
Tester: Shahjalal Shohag, Rumman Mahmud, Raihat Zaman Neloy, Muhiminul Islam Osim
Category: Ad-hoc
Total Solved: 249
First to Solve: IUT cgpa matters
According to the problem statement we need to find the smallest i such that max(a[1], a[2], ..., a[i − 1]) < a[i] <
min(a[i + 1], a[i + 2], ...a[n]). To find it, we can keep two array where one will track the maximum from 1 to
i − 1 and the other array will track the minimum from i + 1 to n. The special cases are if such i is the first or
last element in the given array.
Problem J: The Taxman
Problem Setter: Aminul Haq
Tester: Rumman Mahmud, Muhiminul Islam Osim
Category: Binary Search, Math
Total Solved: 159
First to Solve: DU Singularity
This problem can be solved either purely through math or by using binary search combined with a bit of
math.
For the binary search approach, we can search for the closest income that generates the given tax. The
search boundary is adjusted based on the difference between the tax calculated for our current value and the
input tax. The lower bound of the search is 12,500, and the upper bound is approximately ≈ 3 × 109 . With
the given constraints, we found that 60 iterations are sufficient to produce the accepted output.
Special case: For 0, any value between 0 and 12500 is accepted.
double binarySearch(double target) {
double low = 12500;
double high = 3e9;
int iterations = 60;
while(low <= high && iterations-- > 0) {
double mid = (low + high) / 2;
double tax = calculateTax(mid);
if(tax > target) {
high = mid;
} else {
low = mid;
}
}
return low;
}
For the math-based solution, we can calculate the income range where the salary falls by precomputing the tax
for each range. For example, for an income of 50,000, the tax is 7,500.00, and for 125,000, the tax is 42,500.00.
By comparing the input tax with these precomputed values, the target salary can be directly determined.
One helpful observation here is that the income range from over 100,000 to 125,000 is effectively taxed at 60%,
due to the reduction and taxation of the personal allowance.
6
ICPC Dhaka Regional Contest, 2024 Editorial
Hosted By: Daffodil International University
Problem K: Packet Transmission
Problem Setter: Ashraful Islam
Tester: Pritom Kundu, Nafis Sadique
Category: Lowest Common Ancestor
Total Solved: 0
First to Solve: N/A
Every query we receive can be classified in the following way.
• The query packets (source, destination pair) share a common path in the tree.
■ The packets are going in the same direction. In that case we need to assume one of the packets will
never wait. So, the other packet will arrive at the first vertex of the common path, wait for the first
packet to arrive and then go after it. Since an edge can’t be used by multiple packets at the same
time, the other packet will have to wait until the first packet crossed that edge. Keep doing that
until they reach the end of common path and then they can go their own ways. If we think carefully,
we can see that the other packet will have to wait an additional time totalling the maximum edge
cost on the common path. However if the first packet comes early then the wait time reduces. Do
the same the other way around and take the minimum of the two.
■ The packets are going in the different directions. So, we need both packets to start their journey.
Eventually they might meet on the two sides of an edge where if one starts crossing, the other
must wait. Make one of them wait and the other one go and calculate the time it would take for
both them to reach their destinations. Do it both ways and take the minimum time. However if
they don’t meet at the edge then they don’t have to stop and their actual time to reach both their
destinations is the answer.
• The query packets use completely different paths. In that case the time it takes for both to reach their
destination is the answer.
We can calculate all of these using Sparse Table to calculate Least Common Ancestors in a tree. Alternatively
we can use heavy-light decomposition, but that may be very slow. There are lot of corner cases, so careful
implementation is necessary.
Problem L: Unhappy Team
Problem Setter: Nafis Sadique
Tester: Shahjalal Shohag, Rumman Mahmud, Jubayer Rahman
Category: Dynamic Programming
Total Solved: 0
First to Solve: N/A
The trick is to select the unhappiness score of someone and count how many times that score appear in
the top K values. We can keep a DP state (bit mask, bigger scores count, selected score appeared). Basically
we will put people one after another, everytime calculating their unhappiness score. If the score is smaller than
the selected score then we ignore it. If the score is bigger then bigger scores count is incremented by one. If
the score is the same is the selected score then we can consider it as bigger or mark selected score appeared
as true. This DP will have the complexity of O(2n · n3 ). With some other minor optimizations, this runs
reasonably fast.