By RussianCodeCup, 7 years ago, translation, In English

Hi, everyone!

On September 10, 2017 at 13:00 Moscow time the final round of Russian Code Cup 2017 will take place! The round will be 3 hours long. 55 participants of the final round will compete for prizes and glory, and we are eager to watch their competition at http://russiancodecup.ru.

And we have a nice surprise for the others: if you would like to apply your skills at our finals problems, come to codeforces.com after the Finals is over, at 16:35 Moscow time, the round featuring RCC Finals 2017 problems will take place, open for everybody.

Some notes:

  • Round will use ACM rules;
  • It will be unrated;
  • Problem difficulty will be close to Div 1 round;
  • We ask RCC finalists not to publish or discuss problems after the end of the Finals before the CF round ends, of course you shouldn't participate in CF round;
  • Judging machines at RCC and CF are different, "my solution passed/failed at CF, and it was different at RCC" is not a valid appeal.

UPD The official contest is over, congratulations to the winners! And good luck to CF Round participants.

UPD2 Editorial

Full text and comments »

  • Vote: I like it
  • +113
  • Vote: I do not like it

By andrewzta, history, 7 years ago, translation, In English

Hi all!

During Elimination Round of Russian Code Cup 2017 we had a technical issue that caused almost all problem A solutions sent for evaluation from 5-th to 10-th minute of the contest be accepted.

We found that issue when it was already too late, so it wouldn't be fair to rejudge the solutions. However, we understand that this issue created unfair circumstances for other contestants, that could lose to those lucky ones that submitted in the described time frame.

We have rejudged all solutions after the round, and tried to simulate how could the contest proceed should they have been judged correctly. Of course, any simulation of this kind cannot be accurate, and there is no completely fair resolution. We have decided to do the following:

1) Increase the number of Final Round participants to 55. It gives partial compensation to those participants who could have qualified but failed to do so because of someone's incorrectly small penalty.

2) Increase number of t-shirts to 205. So all participants who have at least 3 accepted problems get our branded t-shirt.

Judges and the technical group of Russian Code Cup are sorry about the issue. We will do our best to avoid anything like that in future.

Good luck to all finalists in the Final Round that will take place in September 2017!

Full text and comments »

  • Vote: I like it
  • +196
  • Vote: I do not like it

By RussianCodeCup, history, 7 years ago, translation, In English

A. Small Numbers

First of all, find prime factorization of numbers a and b.

After that you need to notice that if ab is divisible by p2, (where p is a prime number), it is either possible to divide both a and b by p instantly, or you will need to perform one of the latter two operations first to move one of p factors to the other number, and then divide both by p.

Obviously, parity of occurrence of prime numbers in the multiple ab remains unchanged in all operations. Therefore we can either remove p factor completely from ab or leave it occurring only once. After removing all primes, lets say the ones left are p1, p2, ..., pn. Let us call multiple of all these numbers d. Important observation is that n can't exceed 14 because multiple of first 15 prime numbers is more than 1018, which means it can't be a product of two numbers a, b ≤ 109. Now we simply need to iterate over all possible pairs and chose one with minimum sum that we can obtain from d. This can be done in O(2n) which fits the time limit.

B. New Keyboard

Let us use dynamic programming. The state is d[i][j][k], where i — is the flag that denotes the previous action (0 for layout switch, and 1 for typing character), j is the number of the current layout, and k is the number of characters typed so far. The value is the minimal time to reach the state.

Now iterate over k. For a given k first iterate j from 1 to n twice. Both times relax d[0][j % n + 1][k] = min(d[0][j % n + 1][k], min(d[0][j][k] + b, d[1][j][k] + a)). Two iterations of j from 1 to n are needed to ensure that if the layout switches from n to 1 it is processed correctly.

Now iterate j from 1 to n again and relax values for k + 1. If there is the k-th character of the message in the j-th layout, update d[1][j][k + 1] = min(d[0][j][k], d[1][j][k]) + c.

The answer is min(d[1][j][m]), where m = length(s), for all j from 1 to n.

C. Folding the Figure

Note that there are exactly 4 possible folding lines: two horizontal and two vertical, because the figure must be at one side of the folding line, and must touch it.

Take any square of the folded figure with the minimal x-coordinate. Let it be the cell (xi, yi). Take line x = xi as the folding line. Now we need to find k - n squares of the original figure on the other side of the folding line. So let us find k - n connected squares of the folded figure containing the square (xi, yi), for example, using DFS.

D. Acute Triangles

To count the number of acute triangles let us count the total number of triangles and subtract the number of right and obtuse triangles. For the purpose of this problem let us consider three points on a line to be a degenerate obtuse triangle.

The total number of triangles is equal to the number of ways to choose 3 points of n.

Now note the fact: each right or obtuse triangle has exactly one right or obtuse angle. So the number of bad triangles is equal to the number of bad angles.

Now let us count the number of angles not less than 90 degrees with vertices in the given points. Consider the angle vertex and sort other points by their polar angle relative to the chosen point. Now use two pointers: consider the first of the other two points, the matching third points form a continuous segment along the circle, and its ends move in the same direction.

Time complexity is O(n2log(n)).

E. Joining Arrays

Let us consider two solutions for the problem, that take O(k2·log(k)) and O(k2) respectively. The first one brings up core ideas, while the second one being more elusive has simpler implementation.

O(k2·log(k)) solution:

Consider three main steps of the solution

  1. For each array X (A or B) and each length 1 ≤ length ≤ |X| find minSubsequenceX[length] — lexicographically smallest subsequence of X that has the given length;
  2. Iterate over t such that 1 ≤ t ≤ min(k - 1, |A|) and 1 ≤ k - t ≤ |B|, take minSubsequenceA[t] and minSubsequenceB[k - t], join them;
  3. Joining the given sequences, get the optimal sequence of length k, update the answer with that sequence.

1) To find minSubsequenceX[length] for each length, let us do the following:

  • Calculate next[i][c] that will store the next occurence of value c after i in X;
  • Calculate firstSymbol[length][i] — the first character of lexicographically smallest subsequence of X[i..|X| - 1] that has given length. To calculate it note the following:
    • If j1 = next[i][1], and it exists, then firstSymbol[1][i], firstSymbol[2][i], ... firstSymbol[|X| - j1][i] are equal to 1;
    • If, if j2 = next[i][2], and it exists, then firstSymbol[|X| - j1 + 1][i], ..., firstSymbol[|X| - j2][i] are equal to 2;
    • ...
    • If j3000 = next[i][3000], and it exists, then firstSymbol[max(|X| - j1, |X| - j2, ..., |X| - j3000 - 1) + 1][i], ..., firstSymbol[|X| - j|alphabet|][i] are equal to 3000.
  • After that we can use firstSymbol[length][i] to restore lexicographically smallest subsequence of each array, one by one.

This step takes O(|X|2).

3) Given two lexicographically minimal subsequences SA and SB, now we need to join them to lexicographically smallest sequence. Let us use two pointers p1 and p2. If SAp1 ≠ SBp2, we move the smaller pointer, appending the value it points at to the answer. If SAp1 = SBp2, use binary search to find the longest common prefix of SA[p1..|SA|] and SB[p2..|SB|], and compare the following elements. Use hashes to compare subarrays of SA and SB.

This step takes O((|SA| + |SB|)·log(max(|SA|, |SB|))) = O(k·log(k)).

So the total time complexity is O(|A|2 + |B|2 + k2·log(k)) = O(k2·log(k)).

O(k2) solution:

Let us index arrays, let array A have number 0, and array B have number 1. Let us build the answer one element after another, and maintain the values dp[i][j], where i is the number of the array (0 or 1), j is the index in this array, dp[i][j] is the minimal index in array 1 - i, that can be appended to the answer, if we are at index j in array i.

At the t-th of the k iterations we find the minimum element that can be appended to the answer, and still the answer can be completed by adding another k - t - 1 elements. Also we must note that both subsequences from the two arrays must be non-empty.

After adding the element v, update the dp values in O(|A| + |B|). To do it, use next array, the same as in previous solution.

F. Two Trees

There is a requirement that k-subtree must have a vertex at depth k. Let us temporarily remove this limitation.

Consider all k-subtrees for some value of k. They can be divided to equivalence classes. Let each vertex v have ck[v] — the label of its equivalence class that its k-subtree belongs to.

If k = 0 all c0[v] are the same, because 0-subtree of any vertex is this vertex by itself.

If k = 1 then c1[v] is the number of children of v .

Now let us see how we can convert arrays ck[v] and cm[v] to an array ck + m[v]. First let us assign the array arrk + m[v] to each vertex v, that will uniquely identify its k-subtree. Let u1, ..., us be its descendants of level k in DFS order. Then arrk + m[v] = ck[v], cm[u1], ..., cm[us]. So its (k + m)-subtree is identified by its k-subtree and m-subtrees from the bottom vertices of its k-subtree. See the picture below for k = 3 and m = 1.

To get the list of descendants at level k, let us run one DFS from the root, when entering the vertex, put it to its k levels ancestor list.

To transform arrk + m[v] to integers ck + m[v] we can either use hashing, or trie, or unordered_map. Each vertex is considered only once in each of these arrays, so the total time is O(n).

Given array ck[v] it is easy to check whether there are two equal k-subtrees. To do it you must find two vertices with the same ck, considering only vertices that have descendants of level k (now we need to bring back this requirement).

To find the maximal such k, let us first count c1[v], c2[v], ..., c2t[v] (2t is the maximal power of 2 not exceeding n). After that make some kind of binary ascending by k: start with k = 0, and try to add 2t, 2t - 1, ..., 20, one by one.

Time complexity: O(nlog(n)).

Full text and comments »

  • Vote: I like it
  • +26
  • Vote: I do not like it

By RussianCodeCup, history, 7 years ago, translation, In English

Ready, steady, go!

It's time to find out who the top 50 participants to compete in the Final Round of Russian Code Cup 2017 are. We invite everyone qualified to take part in the Elimination Round this Sunday, May 14, 2017 at 13-00 Moscow Time. Round length is 2 hours. We invite you to russiancodecup.ru, and wish you good luck!

Full text and comments »

  • Vote: I like it
  • +84
  • Vote: I do not like it

By RussianCodeCup, history, 7 years ago, translation, In English

A. Spreadsheets

Let us subtract 1 from k, now the columns are numbered from 0.

Let us first find out how many characters are there in the name of the column. To do it let us subtract powers of 26 from k, one by one, until the current power is greater than the remaining number k'.

Now the name of the column is k' in 26-based notation where characters A–Z are used as digits, prepended with leading A-s to the required length. You can either convert it using standard library function (in this case you must replace digits 0–9, A–P that will be used by the required digits), or implement a textbook algorithm of conversion to another base.

Final note: a day before the round one of the testers pointed out that CF Beta 1 Round problem B was similar to this one. After a discussion, taking into account that CF1 round was long ago, the problem is actually easier than CF1B problem, and we had no well prepared and easy enough replacement problem, we decided to keep the problem.

B. Mortal Combat

Let us count how many hit points the boss loses if attacked by the i-th hero: pi = ai·⌈ hi / A⌉. Sort heroes by non-increasing of pi and send them to attack the boss in this order.

C. A Bit Palindromic Numbers

Let us find out how to count a bit palindromic numbers among the first n positive integers. Now to solve the problem for the range from l to r we count the number of a bit palindromic numbers among first r, among the first l - 1, and subtract the latter from the former.

All numbers from 1 to 9 are a bit palindromic, so if n ≤ 9 the answer is n. Otherwise let us add 9 to the answer and count a bit palindromic numbers from 10 to n. Let us consider ten integers from 10k to 10k + 9, where k ≠ 0. Only one of them is a bit palindromic, the one that has the same first digit as k. So there is one a bit palindromic number from 10 to 19, one from 20 to 29, and so on.

Let n = 10k + d, where 0 ≤ d ≤ 9. So if d is greater or equal to the first digit of k, there are k a bit palindromic numbers from 10 to n, if it is less then the first digit of k, there are k - 1 such numbers.

D. Tree and Polynomials

Let us walk through the key ideas of the solution.

First, notice that6 you can solve problem independently for the two types of the queries. That is because operations don't depend on the values in the vertices.

Second idea is the following. Instead of storing particular values in the vertices, let us store polynomial that must be evaluated from it depth to get the value.

We cannot process queries directly, considering all vertices affected by a query, and adding the query polynomial to the polynomial in the vertex: that would take O(n2·k) which is too slow. Let us use lazy propagation then.

For the queries of the first type we need to add a polynomial q(t) to each vertex in a subtree of v. Let us just store information about that: for each vertex v let us store push1[v] that has the sum of all polynomials that affected the vertex v in queries of the first type.

Simultaneously let us store the sum of all affecting queries of the second type as a polynomial push2[v] for each vertex v.

Now denote as sum1[u] the sum of all polynomials that affect vertex u in queries of the first type.

To calculate sum1[u] let us run DFS from the root, and keep track of a polynomial cur. Entering the vertex v add push1[v] to cur, leaving v subtract it back. When we have entered the vertex u, assign sum1[u] = cur.

Similarly, denote as sum2[u] the sum of all polynomials that affect the vertex u in queries of the second type.

To calculate sum2[u] also use DFS, sum2[u] is equal to the sum of values sum2[v] for all children of u, and the value push2[u].

After we have calculated polynomials sum1[u] and sum2[u] for each vertex, evaluate them on d[u] and add the results, that is the answer for that vertex.

Time and memory are both O(nk).

E. Nice Report

Let's solve one additional problem before proceeding to the main one. You are given a sequence (a1, a2, ..., an) of some objects and somebody asks you to find out how many different objects are presented in this sequence. However, some restrictions apply to the ways you are allowed to process given data:

  1. once the object ai is read, it's lost forever: the next read will return ai + 1 and there is no way to obtain ai again;
  2. you can only use O(1) additional memory

To solve this subproblem we will use the fact that expected value of minimum of m value uniformly distributed over segment [0;1] is 1 / (m + 1).

Consider a hash function h: A → [0;1] which transforms objects ai to some number from [0;1]. Define M as M = min {h(a1), h(a2), ..., h(an)}. This value can be transformed to the problem solution as 1 / M - 1. However, we could run out of luck and end up in the situation where some h(ai) is too small and spoils the answer too much. To deal with it, we can average the answer over several runs with different hash functions h1, h2, ..., hk for some fixed k.

First, let's solve the case of acyclic graph. Any acyclic graph has topological sort: vertices order that respects edge directions: only edges from latter vertices to earlier ones exist. Let's label each vertex with some random number uniformly distributed over [0;1]. Topological sort existence allows us to calculate the minimal reachable label Mi for each vertex by some kind of dynamic programming. After this calculation, we can approximate the number of reachable vertices from i as 1 / Mi - 1. Again, we need to average results from several iterations to improve answer precision.

But given graph can contain cycles. To create an acyclic graph we can build the graph condensation by compressing strongly connectivity components. In the condensed graph each vertex i corresponds to wi vertices in the original graph. To finally solve the problem we'll change vertex labeling phase a bit: a simple random label becames minimal value from wi random value from [0;1] rolls.

A curious reader can find more information related to this problem by reading an article "Size-Estimation Framework with Applications to Transitive Closure and Reachability" located at http://cohenwang.com/edith/Papers/tcest.pdf.

Full text and comments »

  • Vote: I like it
  • +36
  • Vote: I do not like it

By RussianCodeCup, history, 7 years ago, translation, In English

Hi, everyone!

There are already more than 400 participants who are preparing for the Elimination Round of Russian Code Cup 2017. If you are still among those who has not qualified yet, we invite you to take part in the Third Qualification Round that will take part this Saturday, April 29, at 14-00 Moscow Time. Top 200 participants will also qualify to the Elimination Round and will be able to compete to get to the Final Round of Russian Code Cup 2017.

Good luck and see you at russiancodecup.ru!

Full text and comments »

  • Vote: I like it
  • +56
  • Vote: I do not like it

By RussianCodeCup, history, 7 years ago, translation, In English

A. Very Important Persons

There are two main ways to solve the problem.

The first way is to assign guests to seats by diagonals, starting from the seat (1, 1). You should be careful with considering cases n < m and m < n when implementing traversal.

The second way is a more common solution which however requires more advanced algorithm. Let us run BFS from (1, 1) and assign seats to guests in order they are popped from the queue, starting from the most important one.

B. Least Common Multiple

Let p / q be divisible by both a / b and c / d, all fractions are irreducible. So the numbers (p / q): (a / b) = (p·b) / (q·a) and (p / q): (c / d) = (p·d) / (q·c) are integers.

Since p·b is divisible by q·a, b and a are relatively prime, then p is divisible by a. p and q are also relatively prime, so b is divisible by q. Similar argument allows to conclude that p is divisible by с, and d is divisible by q.

Therefore p is divisible by lcm(a, c), q is a divisor of gcd(b, d). The fraction lcm(a, c) / gcd(b, d) is divisible by both a / b and c / d, and is therefore the smallest such fraction. So the answer is lcm(a, c) / gcd(b, d).

C. Bad Order

You have to add numbers to the given array to convert it to a permutation that requires maximal number of swaps when being sorted by selection sort.

First suppose that the permutation is fixed. Let us find the number of swaps that selection sort makes. Consider permutation as a set of cycles. Let us consider a cycle that contains the minimal number that occupies wrong position. Length of this cycle is greater than 1. After we make a swap, it is split to two cycles: of length 1, and 1 shorter than its initial length. Therefore the cycle of length L will be split L - 1 times, so the number of swaps required is n - c, where c is the number of cycles.

Therefore we must add numbers to the given array in such way that the number of cycles in the resulting permutation was minimal possible. To do it consider the given array as a directed graph, if a[i] = j, add an edge from i to j. The graph is a union of cycles and paths. All cycles in the graph will remain there after we convert the array to a permutation. All paths can be concatenated to a single long cycle (vertices without both incoming and outgoing edges are considered paths of length 0). To do so, order paths arbitrarily, and add an edge from the end of each path to the beginning of the next path. Finally make them a single cycle by adding an edge from the end of the last path to the beginning of the first one.

D. Red-Black Tree

First you must notice a subtle hint in the first sentence of the statement. It is easy to prove (or find in any data structures textbook) that red-black tree with n vertices has O(log(n)) black vertices on any path from the root to a leaf. Let us use this fact in our solution.

Let us call a tree almost red-black if its coloring satisfies all constraints of the red-black tree, except that its root is red.

We can now use dynamic programming to calculate for each subtree the number of ways to color it to become red-black or almost red-black, and to have the number of black vertices on any path from its root to a leaf equal to h.

Let us denote the described number of ways as d[v][h][t], here v is the vertex, h is the number of black vertices on any path from v to a leaf in its subtree, t is the type of coloring, t equal to 0 would, for example, mean that the subtree is red-black, and t equal 1 would mean that the subtree is almost red-black.

Now d[v][h][0] is the product for all u children of v of values (d[u][h - 1][0] + d[u][h - 1][1]). Similarly, d[v][h][1] is the product for all u children of v of values d[u][h][0].

The answer to the problem is the sum for all h of values d[1][h][0].

Since h for all valid colorings is limited by C = O(log(n)), we can consider the number of colorings be zero if h > C.

So we only need O(nlog(n)) states, and O(1) to calculate the result for each state. The time complexity is O(nlog(n)).

E. Array Study

Since there are the same constrains to n and q, let us use n instead of max(n, q). Let us make some observations.

Observation one: the answer to the query is the maximal length of [L, R], such that prefL - 1 = prefR, where prefi = a1 + a2 + ... + ai is the prefix sum of the given array. Let us move from the initial array to the array of prefix sums and for a query [l, r] look for the longest subarray of [l - 1, r] such that prefL = prefR.

Observation two: prefi are quite small ( - n ≤ prefi ≤ n).

Let us make use of queries given offline. Our method will be similar to Mo's algorithm. Split all queries to groups, the i-th group will contain queries [li, ri] such that i·K ≤ li < (i + 1)·K (here K is approximately sqrt(n)). In each group sort queries by their right end. Let us solve the problem separately for each group.

Consider the i-th group, where li is in [Li, Ri]. Let us consider queries by non-decreasing of ri, and maintain two arrays: mostLeft[p] and mostRight[p] — the first after Ri and the last before r occurrence of the prefix sum p. Using these two values, we can find the answer that is subarray of [Ri + 1, r]. To get the complete answer to [l, r] query, let us calculate the answer with the beginning of the required subarray at [l, min(r, Ri)] using mostRight array, and take maximum of that value and the optimal subarray for [R + 1, r].

So it takes O(K·ci + n) to answer all queries of one group, here ci is the number of queries in that group. Adding up all O(n / K) groups, we get the total time complexity O(sum(i = 1... n / K: K·ci + n)) = O(K·sum(ci) + n2 / K). Setting K = sqrt(n) we get O(n·sqrt(n)) complexity.

Full text and comments »

  • Vote: I like it
  • +34
  • Vote: I do not like it

By RussianCodeCup, 7 years ago, translation, In English

Hello everyone!

Top 200 from the First Qualification Round have already advanced to the Elimination Round, but the other paricipants still strive to get there. If you haven't qualified yet, we invite you to take part in the Second Qualification Round that will take place this Sunday, April 16, at 12-00 Moscow Time. Best 200 participants will advance to the Elimination Round, other participants can try again in the Third Qualification Round.

Good luck to everyone, see you at http://russiancodecup.ru!

Full text and comments »

  • Vote: I like it
  • +41
  • Vote: I do not like it

By RussianCodeCup, history, 7 years ago, translation, In English

A. Martian Volleyball

First note that in order to end the game as soon as possible only the currently leading team must get points.

Consider the condition that one of the teams wins. It must score at least k points and have at least 2 points advantage.

So the answer is max(k, min(x, y) + 2) - max(x, y).

B. Painting the Wall

First note that if the maximal length of the continuous segment is L, at least L colors are needed to paint the wall. On the other side L colors is always enough.

Consider a square L × L, fill the first line with integers from 1 to L, fill the following lines with all its possible circular shifts. Use these squares to cover the given wall rectangle like this (L = 4):

1 2 3 4 1 2 3 4 1 2

2 3 4 1 2 3 4 1 2 3

3 4 1 2 3 4 1 2 3 4

...

Now each vertical and horizontal segment of length L or less has all tiles of different colors. All that is left is to bring back the lamps.

C. Magic Artifact

Let us denote advantage that Maxim gets if he finds artifact as ci, so ci = ai - bi.

Let Maxim first complete levels in order 1, 2, ..., n. If he finds the artifact at the i-th level, the time he needs to complete the game is equal to bj plus c1 + ... + ci. So the expected time of completing the game is:

b1 + ... + bn + p1·c1 + p2·(c1 + c2) + ... + pn·(c1 + ... + cn).

b1 + ... + bn doesn't depend on level order, so let us try to make the rest as small as possible. Expanding the sums, we get sum of all ci·pk for such i, k that i ≤ k.

Let us now swap levels i and i + 1 in our order. For the given i among ci·pk terms only the one equal to ci·pi + 1 changes — it is replaced with ci + 1·pi. If the order was optimal, it must be ci·pi + 1 ≤ ci + 1·pi, in the other case it was optimal to swap them and get a better answer. Transform this to:

ci / pi ≤ ci + 1 / pi + 1.

In the optimal answer for all i from 1 to n - 1 this inequality must be satisfied. Therefore it is optimal to sort levels according to the key ci / pi. Note that if pi = 0, you may consider ci / pi = ∞.

Sorting according to the key ci / pi should be done carefully. If the fractions are compared using floating-point division, the case ci = pi = 0 will lead to error because 0 / 0 = NaN. If the fractions are compared using the comparator ci·pk < ck·pi, the case ci = pi = 0 will also lead to error because the result of that comparison will always be false. That means that levels with ci = pi = 0 should be handled separately. Such levels can be completed at any time because they do not affect the result besides fixed terms bi. For example, they can be placed at the end.

After sorting the desired expected value can be found using the formula above, use prefix sums for ci to get it fast.

D. Memory Manager

First for each query qi let us find goi — the minimal j, such that among qj, qj + 1, ..., qi there are at most k different blocks — that would mean that it is possible to place pointers before the j-th query in such way that queries j, j + 1, ..., i are performed immediately. This can be made in O(sum(|qi|)), using, for example, two pointers.

Now let us use dynamic programming, denote as dpi the minimal time needed to perform the first i queries. If goi = 0 then dpi = 0. If the equation is not satisfied, dpi = minj = goi..i(dpj - 1 + sj) — we choose the query j to perform the pointer movement before. Since values goi do not descend, this value can be maintained using either std::set of dpj - 1 + sj, or queue with minimum query support.

E. LISA

First let us consider the problem for given two strings: to solve it calculate the number of occurrences of each letter in the first string, the number of occurrences of each letter in the second string, not including the first letter of the first string and the last letter of the second string, that must be used any way. Now the answer is the product of string lengths, decreased by the sum of values cnt1[letter] * cnt2[letter] for each letter. Let us leave proof as an exercise, such problem was at Northern Subregional Contest of NEERC 2015 http://neerc.ifmo.ru/archive/2015/northern/north-2015-statements.pdf, Problem C. Unlimited participants could solve this problem at Three Quaterfinals Cup.

For n strings similar ideas can be used. Put all strings to a prefix trie, all strings to a suffix trie, the total number of ways to get a string is the product of the number of vertices in these tries. What we need to subtract is similar product of number of occurrences of letters in tries, first/last letters of each word must not be considered.

Now we need to answer segment queries. Let us make sqrt-decomposition, divide all strings to groups based on sum of their lengths. Let us greedily add strings to a group until their sum of lengths is more than sqrt(total sum of lengths). Note that the last string can have a big length.

Now use Mo's algorithm, sort queries using the block of the left end as a key, move right end only forward between left end block changes. To add/remove a string to a trie one must maintain the number of active vertices in a trie subtree for each vertex, and the number of entries of letters to a trie.

Full text and comments »

  • Vote: I like it
  • +33
  • Vote: I do not like it

By RussianCodeCup, 7 years ago, translation, In English

Hi, everyone!

This Sunday, April, 2 at 19-00 Moscow time the First Qualification Round of Russian Code Cup 2017 will take place. 200 top participants will qualify for the Elimination Round, those who wouldn't qualify can still take part in two following qualification rounds.

We have a news for you: we have added Kotlin, Haskell and Free Pascal to our list of programming languages, also you can now submit your Python programs to run in PyPy. Exact versions of compilers and compilation commands are published at the official web site. We are working on adding more programming languages.

Good luck to everyone and see you at http://russiancodecup.ru!

UPD Editorial is published

Full text and comments »

  • Vote: I like it
  • +118
  • Vote: I do not like it

By RussianCodeCup, 7 years ago, translation, In English

Hello, everyone and thank you for participation!

First of all we would like to say sorry for the length of the testing queue during the first hour. We have selected IOIP problems for the Warmup Round — there are many common problemsetters for IOIP and RCC — the round was prepared by Victoria Erokhina (viktoria), Dmitry Filippov (DimaPhil), Stanislav Naumov (josdas), Mikhail Putilin (SpyCheese), Grigory Shovkoplyas (GShark), Andrew Stankevich (andrewzta), Ilya Zban (izban). We wanted to let everyone solve our interesting problems.

But one small glitch lead to a big failure. You might have noticed that we usually make multiple tests in one input data for RCC. That is because the most expensive operation is to run user solution. But IOIP has fewer participants, so the easiest problem had 32 tests. It is not too many for a problem, but during 15 minutes 400 participants submitted the correct solution and our testing machines capacity was not enough.

We decreased the number of tests in the problem, and the situation got better. We will take this into account when preparing problems for future contests.

Now let us proceed to problem analysis.

A. Spaceship

Note that if the last enemy to destroy has power equal to x, the sum of powers of all enemies is 2x. Therefore to find the power of the enemy to destroy last, let us find the sum of all powers and divide it by two. After that just pick any enemy with such power and swap it with the last one.

B. Rangers in the Bus

Let us process passengers one by one. Since Pink Ranger could take any seat, any passenger can be Pink Ranger.

For each seat we want to be able to quickly answer if it is free. Let us use std::set that stores the set of occupied seats. To check whether the current passenger can be Red Ranger let us find the seat that Red Ranger would choose. Iterate row from 1 to n, and if there is a free seat in the current row, take the left seat if it is free, or the right seat in the other case. If the current passenger chose that seat, he could be Red Ranger. Similarly we can check whether the current passenger could be Blue, Black or Yellow Ranger. After processing the passenger, add the seat he chose to the set of occupied seats.

The solution described uses O(nk) time and O(k) memory.

To get rid of time limit, let us note that all we need is to store the minimal and the maximal row that have free seats. Use two indices first and last to store them. Initially first = 1, last = n. After each passenger update these values. Increase first by 1, until the row pointed by first is completely occupied, then similarly decreaser last. There are at most k / 2 occupied rows, so both indices will be changed O(k) times.

C. Magic Weapon

Precalculate arrays: R[a][b] — the number of red details that have the first digit of the model number equal to a and the last digit equal to b; G[a] — the number of green details that have the last digit equal to a; и B[b] — the number of blue details that have the first digit equal to b.

It model numbers of different colors were distinct, the answer would be equal to the sum for all a and b of values G[aR[a][bB[b].

To resolve the situation when some pair of details have the same model number, calculate the number of red-blue pairs with the same model number, red-green pairs and green-blue pairs. Note that only model numbers with the same first and last digit need to be considered. You can use std::map to calculate the number of such model numbers. Now use inclusion-exclusion principle to find the answer: subtract the number of pairs of each type and add back twice the number of triples that all three rangers use detail with the same model number.

D. Knights and Knaves

Let us use dynamic programming with mask of the last two columns as a state. Consider for example subtask of calculating the maximal number of knights.

Let dp[i][mask_prev][mask_cur] be the maximal number of knights that can be positined among the first i columns, where mask_cur is the mask of the i-th column, mask_prev is the mask of the (i - 1)-th. Use bit equal to 1 to denote a knight and 0 to denote a knave.

Try all possible masks for the (i + 1)-th column, check whether constraints for the soldiers in the i-th column are satisfied, because now we know all of their neighbors.

The first and the last columns must be considered separately, because soldiers there don't have one of the neighbors.

Initial values: dp[2][mask_prev][mask_cur] the number of ones in mask_prev and mask_cur, if mask_prev can be before mask_cur.

Updating values: relax dp[i + 1][mask_cur][mask_next] with dp[i][mask_prev][mask_cur] + ones(mask_next), where ones(x) is the number of ones in x.

The answer is the maximum among dp[k][mask_prev][mask_cur], such that mask_cur can be after mask_prev.

Finally, we probably need to consider k = 1 separately, because there is no previsous column for any column in this case.

E. Parallelepiped

Let us give a sketch of the main solution idea. First, separately consider all parallelepipeds that have two or three equal sides. This can be done in O(n).

Now let us consider the case where all three sides are different. Let us build the following undirected graph: vertices are side length, connect a and b if there are at least two sheets of size a × b. Now the problem is reduced to considering all triangles in this graph which can be done in O(n2 / w) or O(nsqrt(n)) time (here w is the word size, 32 or 64 which comes up from bit compression).

Full text and comments »

  • Vote: I like it
  • +23
  • Vote: I do not like it

By RussianCodeCup, 7 years ago, translation, In English

Hi, everyone!

We are pleased to announce Russian Code Cup 2017! Qualification rounds will start in April, the Final round will be held online in September. Each of the three Qualification rounds will allow 200 participants to qualify for Elimination round, top 50 from Elimination round will proceed to Final round. The problems will be both in Russian and in English.

The full schedule of the tournament can be found at http://russiancodecup.ru, you can also register there. Note that you must register for the new season even if you took part in the previous tournaments.

We still have more than two weeks before the first Qualification, so we would like to invite everyone to the warm up round that will take plance on Sunday, March 19, 14-00 Moscow time. Visit http://russiancodecup.ru to take part in the round, it will be 2 hours long.

Good luck to everyone and see you at Russian Code Cup 2017!

UPD: We remind you that the Warmup Round will start at 14-00 Moscow time. Problems of the Warmup Round are based on IOIP problems (Russian contest for high school students, run today at several cities) that are prepared by the same team of authors. We kindly ask students that take part in IOIP to play fairly and not to try to take part in RCC Warmup. Good luck to everyone!

UPD2: Thanks to all participants that made a real stress testing for our judging machines. Unfortunately we had long queues during the first hour, they were fixed, and from the middle of the contest the waiting time in most cases was limited to 2-3 minutes. We will make sure there would be no queues during further rounds.

Full text and comments »

  • Vote: I like it
  • +87
  • Vote: I do not like it