959A - Mahmoud and Ehab and the even-odd game
It's easy to see that if n = 0, the next player loses. If n is even, Mahmoud will choose a = n and win. Otherwise, Mahmoud will have to choose a < n. n is odd and a is even, so n - a is odd. Ehab will then subtract it all and win. Therefore, if n is even Mahmoud wins. Otherwise, Ehab wins. n = 1 doesn't follow our proof, yet Ehab still wins at it because Mahmoud won't be even able to choose a.
Code link (me) : https://pastebin.com/X3D08tg9
Code link (mahmoudbadawy) : https://pastebin.com/4u3RHE7n
Time complexity : O(1).
Bonus task : If there were multiple integers, and each player can choose which integer to subtract from, who will win?
959B - Mahmoud and Ehab and the message
It's easy to see that for every word, the minimum cost of sending it is the minimum cost of sending any word in its group. For each group, we'll maintain the minimum cost for sending a word in it (let it be costi) and for each word, we'll maintain its group (let it be groupi). For every word i in the message, we'll add costgroupi to the answer.
Code link (me) : https://pastebin.com/3RFeEkgD
Code link (mahmoudbadawy) : https://pastebin.com/sR5eZy7d
Time complexity : O((n + m)log(n) * len).
Bonus task : Try to solve the problem if the input was given as pairs of words that are synonyms (assuming synonymy is transitive).
959C - Mahmoud and Ehab and the wrong algorithm
The first tree
For n ≥ 6, you can connect nodes 2, 3, and 4 to node 1 and connect the rest of the nodes to node 2. The real vertex cover is the set {1, 2} of size 2 while the found vertex cover will have size min(3, n - 3). As n ≥ 6, that value will be 3 which is incorrect.
For n < 6, the answer doesn't exist.
The second tree
There are multiple ways to construct it. One easy way is the star tree. Connect all the nodes to node 1. The real and the found vertex cover will be simply {1}. Another easy way is a path. Connect node i to node i + 1 for all 1 ≤ i < n. The real and the found vertex cover has size .
Code link (me) : https://pastebin.com/7J8B9fXx
Code link (mahmoudbadawy) : https://pastebin.com/54jZ8sGM
Time complexity : O(n).
Bonus task : Try to find an elegant proof that the answer for n < 6 doesn't exist for the first tree.
959D - Mahmoud and Ehab and another array construction task
Common things : Let's call a number "ok" if it could be inserted to array b, as a new element, without breaking any of the conditions (i.e it should be coprime with all the previously inserted elements). Let's call the maximum number that could be inserted in the worst case mx. For each integer from 2 to mx, we'll precompute its prime divisors with sieve.
First solution by me
Create an std::set
that contains all the numbers from 2 to mx. That set has all the "ok" numbers and will be updated each time we insert a new element to array b. We'll insert the elements to array b greedily one by one. At index i, let cur be the minimum number in the set greater than or equal to ai i.e std::lower_bound(a[i])
. If cur isn't equal to ai, the lexicographically greater condition is satisfied and we're no longer restricted to a, so, starting from index i + 1, we'll greedily choose cur to be the first (minimum) number in the set instead. We'll insert cur to b. Each time, we'll remove all the integers that aren't coprime with cur from the set. To do that, we'll loop over the multiples of its precomputed prime divisors and remove them from the set.
Code link (me) : https://pastebin.com/bg3Hi6r2
Second solution by KAN
Let used[i] indicate whether some prime is already a factor of one of elements in b (so we shouldn't use it). Each time we insert an element to b, we update used by iterating over its precomputed prime divisors and make them all used. We'll start inserting elements to b greedily one by one. To check if a number is "ok", we'll iterate over its precomputed prime divisors and check that all of them aren't used. While ai is "ok", we'll keep inserting it to b. We'll reach an integer that isn't "ok". In this case, we'll iterate naiively until we find an integer that is "ok" and insert it to b. The lexicographically greater condition is now satisfied and we can insert whatever we want (no restriction to a). Notice that starting from now, b will be sorted in increasing order. That's because if it's not, we can sort it and reach a better answer without breaking any of the conditions. The naiive solution is to loop starting from 2 until we find an "ok" integer for each i. However, as the array is sorted, we can loop starting from 2 the first time and then loop starting from bi - 1 + 1 and save a lot of loops that we're sure will fail!
Code link (me) : https://pastebin.com/Xh2QgqUf
Time complexity : O(mxlog(mx)). mx has an order of because the nth prime is expected to be O(nlog(n)) and the number of primes less that n is expected to be .
959E - Mahmoud and Ehab and the xor-MST
For convenience, let n be the label of the last node not the number of nodes (i.e n = ninput - 1).
Denote lsb(x) = x&( - x) as the value of the least significant bit set to 1 in x. The answer is , which means that node u is connected to node for all 1 ≤ u ≤ n (node u is connected to node u without that bit).
Now let's see how to calculate that quickly.
Math solution
Let f(x) be the number of integers y such that 1 ≤ y ≤ n and lsb(y) = x, then . f(i) > 0 if and only if i is a power of 2 so this sum is equivalent to . Basically, the first number y such that lsb(y) = x is x and then the period is 2 * x. Take 4 to see that. The integers y such that lsb(y) = 4 are {4, 12, 20, 28, etc.} Therefore, for 1 ≤ x ≤ n and x is a power of 2.
Code link (me) : https://pastebin.com/dNuR9k0Y
DP solution
Let's see how the sequence of lsb(x) is constructed. We start with {1} and at the ith step, we copy the sequence and concatenate it to itself and add 2x in the middle.
Let . Let dp[i] = f(2i - 1).
You can see from the pattern above that dp[i] = 2 * dp[i - 1] + 2i - 1 for 1 < i (with the base case that dp[1] = 1). Let's find a recurrence for f(x). Denote msb(x) as the value of the most significant bit set to 1. The sum can be split into 2 parts : the sum from 1 to msb(x) and the sum from msb(x) + 1 to x. You can see that in the second sum, lsb(i) can never be equal to msb(x), so we can remove that bit safely without affecting the answer. Removing that bit is like xoring with msb(x) which makes the sum start at 1 and end at which is . Therefore, . The first part can be calculated with the help of our dp because msb(x) is a power of 2 and the second part goes recursively. Basically, for each i such that the ith bit is set to 1, we add dp[i] + 2i to the answer.
Code link (me) : https://pastebin.com/wnhBZx2v
Time complexity : O(log(n)).
959F - Mahmoud and Ehab and yet another xor task
Let's solve a simpler version of the problem. Assume the queries only ask you to see whether the answer is 0 or positive instead of the exact answer. We can answer all the queries offline. We can keep a set containing all the possible xors of subsequences and update it for each prefix. Initially, the set contains only 0 (the xor of the empty subsequence). For each index i in the array, we can update the set by adding to the set for all x in the set. The intuition behind it is that there's a subsequence with xor equal to x (as x is in the set) and if we add ai to it, its xor will be , so we should add it to the set. That's a slow solution to update the set, but we have some observations:-
- If x is in the set and y is in the set, must be in the set. To see that, let x be the xor of some elements and y be the xor of other elements. must be the xor of the non-common elements (because the common elements will annihilate) so it must be in the set.
- If x is in the set and y isn't in the set, can't be in the set. This could be proved by contradiction. Assume is in the set, then, by the first observation, must be in the set. This is equivalent to y which we said that it isn't in the set. Therefore, isn't in the set.
Basically, if ai is already in the set, we do nothing because updating the set would do nothing but extra operations according to the first observation, and if ai isn't in the set, we don't even waist a single operation without extending the set! That makes the total complexity O(n + maxAi) or O((n + maxAi)log(maxAi)) depending on implementation because each element is added to the set exactly once.
To solve our problem, let's see the naiive dynamic programming solution. Let dp[i][x] be the number of subsequences of the first i elements with xor x. . The intuition behind it is exactly the same as the intuition behind the set construction. Let's prove that dp[i][x] is equal for all x belonging to the set! Let's assume this holds true for i - 1 and see what happens in the transition to i. Notice that it holds true for i = 0. Let j be the value that dp[i - 1][x] is equal to for all x belonging to the set. If ai is in the set, and x is in the set, is in the set (observation #1). Therefore, dp[i - 1][x] = j and which makes dp[i][x] = 2 * j for all x in the set. Notice that the set doesn't change so dp[i][x] = 0 for all x that aren't in the set. If ai isn't in the set, we have 3 cases for x. If x is in the set, isn't in the set. Therefore, dp[i][x] = j + 0 = j. If x is to be added to the set in this step, is in the set. Therefore, dp[i][x] = 0 + j = j. Otherwise, dp[i][x] = 0. To summarize, we'll maintain the set. For each integer, if it's in the set, we'll just multiply j by 2. Otherwise, we'll update the set. We'll then answer all the queries for that prefix (saying 0 or j) depending on whether x is in the set.
Code link (me) : https://pastebin.com/Kfi0NWTi
Time complexity : O(n + maxAi) if you implement the "set" with a vector and an array.
Bonus task : Can you make this solution work online? Can you do that with maxAi < 230?