Kostroma's blog

By Kostroma, 5 years ago, In English

Hello!

Traditionally AIM Tech organizes a big party for Petrozavodsk camp participants to have fun and get an opportunity to communicate with each other. Usually it comes along with a funny contest in unusual format. This year we decided to share the fun with all codeforces community!

This year we came up with a format requiring (probably) less time for preparing the contest. It is somewhat similar to an ordinary contest with a 3-hour duration. We already have some problem ideas, so it should be super easy to prepare the problems just one night before the competition. We hope everything will run smoothly!

The contest will start on Feb/03/2020 19:15 (Moscow time). It could be a bit rescheduled due to onsite delays.

It will be an unrated funny competition. Unlike usual ICPC-style contests, you'll be given an archive with several open test cases and answers for each problem. You'll have some sample test cases in the statement too, they'll be included in the archive. However, the solutions will be tested against both open and hidden tests. The open tests will be published as an encrypted zip-archive in this post. The password will be published just before the start of the contest.

The statements will be in English only because we are running out of time in preparation and have to prioritize things.

It's not 100-percent clear at the moment, but it seems the contest will be somewhat hard, so we recommend it for div. 1 participants. However, div. 2 participants are welcome as always, but we can't guarantee the contest will be a perfect match for them.

It's possible to participate both individually and in teams of maximum 3 persons.

Another point to mention is that the order of problems could be not the same as the order of their difficulties. But we'll try to do so. A bit.

The authors to blame are Kostroma, zemen, Golovanov399, mathbunnyru and ArtDitel.

As you may notice, it is just one night before the competition, so we should start preparing the problems. We hope that we'll manage not to do very stupid bugs in the tests. See you at the competition!

UPD It's still more than 4 hours before the contest, but the open tests are already prepared! You can download the archive using one of the two links: one two. The encrypted archive contains another archive containing the actual tests.

The password will be published here shortly before the start of the contest.

UPD2 We have to move contest 10 minutes forward, because we need to prepare the last problem :(

UPD3 Oops, the contest is about to start, but we still don't have correct solutions! Unfortunately, each authors' solution contains a bug (or even several bugs!). However, we decided not to cancel the competition. We give you the outputs of the model solutions on open tests in the archive. Guess all the bugs in our solutions and get OK for the code with exactly same bugs! Good luck and have fun!

The password to the archive will be published as a clarification in the contest interface.

UPD4 The password to the archive is oops_seems_that_nobody_tested_the_solutions

UPD5 The editorial is published, but it still does contain bugs, wait a bit while it is being debugged.

UPD6 Feel free to share your opinion in the comments! Were the solutions enough buggy? Was it enough hard, or we should've added a couple of hard problems? Do you want to solve such contests in future?

Full text and comments »

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

By Kostroma, 6 years ago, In English

Thanks bmerry for posting his solutions, we gently took some of them as a base for editorial.

Tutorial is loading...

Problem author: VadymKa

Problem developers: riadwaw, malcolm

Code
Tutorial is loading...

Problem author: VadymKa

Problem developers: riadwaw, malcolm, Kostroma, Errichto

Code
Tutorial is loading...

Problem author: malcolm

Problem developers: yarrr, Edvard, malcolm, Errichto

Code

Bonus: Solve the problem, if you need to find intersection of some n - k of n rectangles, if k ≤ 10. Without data structures.

Tutorial is loading...

Problem author: Errichto

Problem developers: zemen, Errichto, Kostroma, riadwaw

Code
Tutorial is loading...

Problem author: zemen

Problem developers: yarrr, Kostroma

Code
Tutorial is loading...

Problem author: Errichto

Problem developers: Kostroma, malcolm

Code
Tutorial is loading...

Problem author: zeliboba

Problem developers: Kostroma, riadwaw

Code
Tutorial is loading...

Problem author: Kostroma

Problem developers: Kostroma, riadwaw, gchebanov, malcolm

Code

Full text and comments »

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

By Kostroma, 8 years ago, translation, In English
Tutorial is loading...
Tutorial is loading...
Tutorial is loading...
Tutorial is loading...
Tutorial is loading...
Tutorial is loading...

Full text and comments »

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

By Kostroma, 8 years ago, translation, In English
Tutorial is loading...
Code
Tutorial is loading...
Code
Tutorial is loading...
Code
Tutorial is loading...
Code
Tutorial is loading...
Code
Tutorial is loading...
Code
Tutorial is loading...
Code

Full text and comments »

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

By Kostroma, 9 years ago, translation, In English

Hello, codeforces!

On the 18-th of November we held the contest made by our company at the MIPT-2015 ACM ICPC Workshop. The problemsetters of the contest are: zeliboba, gchebanov, Kostroma, riadwaw, yarrr, ValenKof, ArtDitel, Endagorion.

On Sunday, November, 29, at 11 a.m. MSK the unofficial translation of this contest will be held on the Yandex.Contest platform. We invite all of you to participate, being quite sure that everyone will find the problems interesting for them.

P.S. You can read more about the MIPT-2015 ACM ICPC Workshop in the Rubanenko blog.

Full text and comments »

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

By Kostroma, history, 9 years ago, In English

572A - Arrays

In this problem one need to check whether it's possible to choose k elements from array A and m elements from array B so that each of chosen element in A is less than each of chosen elements in B. If it's possible then it's possible to choose k smallest elements in A and m largest elements in B. That means that in particular, k-th smallest element of A is less than m-th largest element in B. So, if A[k] < B[n - m + 1] then the answer is "YES" and if not, then the answer is "NO".

Problem author: zeliboba.

Problem developers: riadwaw, Kostroma.

Solution code: 12873382.

572B - Order Book

First of all the problem may be solved for buy orders and sell orders separately.

The easiest soultion is to use structure like std::map or java.lang.TreeMap. To aggregate orders we just add volume to the corresponding map element: aggregated[price] += volume.

After that we should extract lowest (or largest) element from map s times (or while it's not empty).

Complexity of this solution is O(nlogn).

It is also possible to solve the problem without data structres other than an array. You should just maintain at most s best orders in sorted order and when adding another order you insert it in appropriate place and move worse elements in linear time of s. Complexity of this solution is O(sn).

Problem authors and developers: ArtDitel, yarrr.

Solution code: 12873385.

571A - Lengthening Sticks

Let's count the number of ways to form a triple which can't represent triangle sides, and then we subtract this value from — the total number of ways to increase the sticks not more than l in total. This number is obtained from partition of l into 4 summands (la + lb + lc + unusedl = l), or can be counted using a for loop.

Now we consider triples a + la, b + lb, c + lc, where la + lb + lc ≤ l, la, lb, lc ≥ 0. Fix the maximal side, for example it would be a + la. We'll have to do the following algo for b + lb and c + lc in the same way. The triple is not a triangle with maximal side a + la if a + la ≥ b + lb + c + lc. If we iterate over la between 0 and l, we have the following conditions on lb, lc:

lb + lc ≤ a - b - c + la, 
lb + lc ≤ l - la, 

lb, lc ≥ 0. So, non-negative integers lb, lc should be such that lb + lc ≤ min(a - b - c + la, l - la). If we denote this minimum as x than we can choose lb, lc in different ways (again we divide x into three summands: lb, lc and some unused volume). Also when we fix lb, there are x - lb + 1 ways to choose lc, so the overall number of pair lb, lc is

so we obtain the same formula.

To sum up, we need to iterate over the maximal side and over the addition to that side, then write these formulas, and subtract the result from the total number of different additions to the sides. The complexity of the solution is O(l).

Problem author: Kostroma.

Problem developers: Kostroma, riadwaw.

Solution code: 12873406.

571B - Minimization

We can divide all indices [1;n] into groups by their remainder modulo k. While counting , we can consider each group separately and sum the distances between neighbouring numbers in each group.

Consider one group, corresponding to some remainder i modulo k, i.e. containing aj for . Let's write down its numbers from left to right: b1, b2, ..., bm. Then this group adds to the overall sum the value

We can notice that if we sort b1, ..., bm in non-decreasing order, this sum will not increase. So, in the optimal answer we can consider that numbers in each group don't decrease. Furthermore, in that case this sum is equal to |bm - b1|.

Now consider two groups b1, ..., bm and c1, c2, ..., cl, both sorted in non-decreasing order. We claim that either b1 ≥ cl or bm ≤ c1, i.e. segments [b1, bm] and [c1, cl] can have common points only in their endpoints.

Why is this true? These groups add |bm - b1| + |cl - c1| to the overall sum. We consider the case c1 ≥ b1, the other is symmetric. If c1 < bm, then swapping c1 and bm will not increase the values these groups add to the answer, since the right border of b group moves to the left, and the left border of c group moves to the right. So, c1 ≥ bm in that case, and the assertion is proved.

Now we know that the values in each group should from a continuous segment of the sorted original array. In fact, we have groups of size (so called small groups) and groups of size (so called large groups). Consider the following dynamic programming: dp[L][S] — the minimal sum of values added to the answer by L large groups and S small groups, if we choose the elements for them from the first elements of the sorted array A. There are no more than O(k2) states, and each transition can be made in O(1): we choose large or small group to add and obtain the number it adds to the sum by subtracting two elements of the sorted array. The answer for the problem will be in .

The overall complexity of the solution is . We can note that in pretests was quite small, and some slower solutions could pass, but they failed on final tests.

Problem author: zeliboba.

Problem developers: Kostroma, riadwaw.

Solution code: 12873418.

571C - CNF 2

Firstly let's assign values to variables occurring in our fomula only with negation or only without negation. After that we can throw away the disjuncts which contained them, since they are already true, and continue the process until it is possible. To make it run in time limit, one should use dfs or bfs algorithm to eliminate these variables and disjuncts.

So now we have only variables which have both types of occurrences in disjucnts. Let's build a graph with the vertices corresponding to disjuncts, and for each varible a make an edge between the disjuncts that contain a and !a. Now we should choose the directions of edges in this graph in such a way that every vertex has at least one incoming edge.

We can notice that if some connected component of this graph is a tree, the solution is not possible: on each step we can take some leaf of this tree, and we have to orient its only edge to it, and then erase the leaf. In the end we'll have only one vertex, and it'll not have any incoming edges.

Otherwise, take some cycle in the component and orient the edges between neighbouring vertices along it. Then run dfs from every vertex of the cycle and orient each visited edge in the direction we went along it. It is easy to easy that after this process every vertex will have at least one incoming edge.

So, we should consider cases with the variables which values can be assigned at once, than construct a graph from disjuncts and variables and find whether each connected component has a cycle. If so, we also should carefully construct the answer, assigning the remaining variables their values, looking at the directions of the edges in the graph. The overall complexity is O(n + m).

Problem author: zeliboba.

Problem developers: Kostroma, zeliboba, yarrr.

Solution codes: 12873432 (linear solution), 12873446 (), 12873456 (matching solution).

571D - Campus

Let's suppose for each dormitory from Q query we already know the last raid moment.

When task will be much easier: we can throw away M and Z queries and to get right answer we should subtract two values: people count in dormitory right now and same count in a last raid moment.

On this basis, we have such plan:

  1. For each Q query let's find the last raid moment using M and Z queries.
  2. Find people count in two interesting moments using U and A queries.
  3. Calculcates the final answer.

Let's try to solve the first part.

We want to make such queries on disjoint sets:

  1. Merge two sets (M query).
  2. Assign value time for all elements in particular set (Z query).
  3. Get value for a particular element (Q query).

To solve this task we'll use a well-known technique: "merge smaller set to bigger".

We'll maintain such values:

  • elements — set elements.
  • set_id — for each element their set id.
  • last_set_update_time — last moment when assign operation has occurred for each set.
  • last_update_time — last moment when assign operation has occurred for each element.
  • actual_time — moment of time when last_update_time was actually for the element.

Let's focus on actual_time value.

It's obvious that when we merge two sets each element can have a different last assign moment. But after first assignment all elements from any set will have the same value. So the answer for Q query for element i from set s: If last_set_update_time[s]=actual_time[i] then last_update_time[i] else last_set_update_time[s]

For each Z query you should just update last_set_update_time array.

It's easy to maintain this values when you merge two sets:

Let's suppose we want to merge set from to set to. For each element from set from we already know last assign time. So just update last_update_time with this value and actual_time is equal of last assign operation for set to.

The second part of the solution is the same as first one.

O(n * lg(n) + m) time and O(n + m) memory.

Problem author: ArtDitel.

Problem developers: yarrr, gchebanov, Kostroma.

Solution codes: 12873477 (solution, described in the editorail), 12873469 (solution with treaps).

571E - Geometric Progressions

If intersection of two geometric progressions is not empty, set of common elements indexes forms arithmetic progression in each progression or consists of not more than one element. Let's intersect first progression with each other progression. If any of these intersections are empty then total intersection is empty. If some of these intersection consist of one element, then we could check only this element. Otherwise one could intersect arithmetic progressions of first progression indexes and take minimal element of this intersection. The remaining question is how intersect two geometric progression? Let's factorise all numbers in these two progressions and find set of appropriate indexes for every prime factor in both progressions. These progressions one need intersect both by values and by indexes.

Problem author: zeliboba.

Problem developers: zeliboba, yarrr, gchebanov.

Solution code: 12873480.

Full text and comments »

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

By Kostroma, 11 years ago, translation, In English

Div2-A

Create an array used of 100 elements. i-th element for the segment (i, i + 1).

For every student except Alexey set used[i]  =  true for each segment (i,  i  +  1) in the segment of that student. After that for each subsegment (i,  i  +  1) of Alexey's segment add 1 to result if used[i]  =  false.

Div2-B

First of all, calculate how many L's we can bring so that the result will not exceed N. It's .

Now, if R·K  ≥  N we may increase any of K numbers by 1. At some moment sum will be equal to N becase sum of K R's is greater than N. So answer in this case is YES.

If R·K  <  N, we can't get K or less numbers because their sum is less than N. But we can't get more than K numbers too, because their sum is more than N. So answer is NO.

Complexity: O(1) for every query. Overall complexity: O(t).

Div1-A/Div2-C

Let's factorize all n numbers into prime factors. Now we should solve the problem for every prime independently and multiply these answers. The number of ways to split pk into n multipliers, where p is prime, is equal to C(k  +  n  -  1,  n  -  1) (it can be obtained using the method of stars and bars, you can read about it here, choose 'combinatorics'). So we have a solution that needs time.

Div1-B/Div2-D

First of all, let's consider n  +  1  =  p is prime. Then we can prove by induction that the answer is . Base for p  =  3 is obvious. If this equality holds for p, and q is the next prime, then answer for q is equal to answer for p plus q  -  p equal summands , that is , that's we wanted to prove.

Next using that the distance between two consecutive primes not exceeding 109 does not exceed 300, we can find the answer as a sum of the answer for the maximal prime not exceeding n and several equal summands . We see that the denominator is a divisor of 2pq, which fits in long long.

Div1-C/Div2-E

We can write all vertices in the list in order of dfs, then the descendants of the vertex from a segment of this list. Let's count for every vertex its distance to the root level[v].

Let's create two segment trees st1 and st2. If we are given a query of the first type, in st1 we add x  +  level[vk to the segment corresponding to the vertex v, in st2 we add k to the segment corresponding to the vertex v.

If we are given a query of the second type, we write st1.get(v) - st2.get(v) * level[v].

The complexity is O(qlogn).

You can use any other data stucture that allows to add to the segment and to find a value of an arbitrary element.

Also there exists a solution using Heavy-Light decomposition.

Div1-D

Let's prove a useful fact: sum of number of invertions for all permutations of size k is equal to . The prove is simple: let's change in permutation p for every i pi to k  +  1  -  pi. Then the sum of number of invertions of the first and the second permutations is , and our conversion of the permutation is a biection.

Now we suppose that we are given a permutation of numbers from 0 to n  -  1.

Let's go at p from left to right. What permutations are less than p?

  • Permutations having first number less than p0. If the first number is a  <  p0, than in every such permutation there are a inversions of form (first element, some other element). So in all permutations beginning with a there are a·(n  -  1)! inversions of this from. Moreover, there are inversions not including the first element, their sum is sumAll[n  -  1]. Then, counting sum for all a we have inversions.
  • Permutations beginning with p0. At first, we should count the number of inversions, beginning in p0. There are cnt·p0 of this form, where cnt is the number of permutations beginning with p0 and not exceeding p. Then we should count the inversions not beginning in the beginning. But it is the same problem! The only exception is that if p1  >  p0, there are p1  -  1 available numbers less than p1, but not p1. So we get a solution: go from left to right, keep already used numbers in Fenwick tree, and then solve the same problem, assuming that the first number is not pi but pi - (the number of used numbers less than pi).

The last we should do is to count the number of permutations not exceeding the suffix of p and beginning the same. It can be precomputed, if we go from right to left. In this case we should do the same as in the first part of solution, but consider that the minimal number is a number of already used numbers less than current.

Div1-E

We will describe an algorithm and then understand why it works.

For every prime we will maintain a list of intervals. At the first moment for every pi we add in its list interval [0;ai), other primes have an empty list.

Then we go from big primes to small. Let's consider that current prime is p. If in its list there exists an interval [x;y), $x < k, y > k$, we divide it into two parts [x;k) and [k;y).

Then for every interval [x;y), x  ≥  k (in fact, in this case x  =  k) we add to the answer for p y  -  x. For intervals, where y  ≤  k, we add to list of every prime divisor of p  -  1 invterval [x  +  1,  y  +  1). If p  -  1 has some prime if more than first power, we should add this segment several times.

After that we should conduct a "union with displacement" operation for every prime which list was changed. If in one list there are 2 invervals [x,  y), [z,  t) so that y  ≤  z  >  x, we replace them with one interval [x,  y  +  t  -  z) (so we added t  -  z to the right border of the first interval). Then we go to next (lesser) p.

Why does it works? If we take function φ one time, for every prime p which divides n, n is divided by p and multiplied by p  -  1 (or, the same, by all prime divisors p  -  1 in corresponding powers).

Now we can observe that intervals in lists contains the numbers of iterations, when the number contains the corresponding prime number. Bigger primes do not affect smaller, so we can process them earlier. If after i-th iteration the number contains prime number p, after i  +  1-th iteration it contains prime divisors of p  -  1, and we add segments in accordance with this. The k-th iteration is the last, so the existence of the interval [k,  x) means that after k-th iteration we have (x  -  k)-th power of this prime. From this it is clear why we unite the intervals if that way.

Why does it work fast?

  1. Because we precalculated the minimal prime divisor of each number up to MAXPRIME using linear Eratosthenes sieve. (Well, it's not necessary)

  2. Because for each prime there's no more than intervals, because for each [a,  b) range . Practically there is no more than 6 segments at once.

Any questions about the editorial are welcome! Especially the English one :)

This post was restored from google cache, and I have edited formula once again. If you notice some mistake, please send be a private message.

Full text and comments »

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

By Kostroma, 12 years ago, translation, In English

AVasya and the Bus

Firstly, if n = 0, then children can't be in the bus, so if m = 0 then the answer is (0, 0), otherwise the answer is "Impossible". Now n > 0. If m =  = 0, than it is only one possible variant of passage — the answer is (n, n). Otherwise, more grown-up take some children, less the sum that people pay. So, if only one adult takes all children, than we get maximal sum — n + m - 1. Maximum min(n, m) adults can take the children with them, so the minimal answer is n + m - min(n, m) = max(n, m).

BSurrounded

Let's find the minimum distance between two circles L. Then the answer to our problem is L / 2.
Now d is the distance between the centers of the circles, R, r — their radiuses. There are 3 possible cases:
- Circles don't intersect. Then L = d - R - r. Firstly, it's reachable: let's consider the segment, connecting the centers of the circles, and take its part, which is out of both circles — its length is exactly d - R - r.

Let's prove that lesser distance is impossible. If the segment connecting two points of distinct circles have length l, than R + l + r >  = d, so l >  = d - R - r.

- If one circle is into another, than analogically the answer is R - d - r, where R is the radius of the bigger circle.
- If the circles intersect, then the answer is 0.

CSTL

In this problem we have an array of strings (s1, s2, ...sn), where si  = pair or int.
Let's consider bali = the difference between number of "pair" and "int" int the subarray (s1, s2, ...si).
Than we can prove that the type can be reestablished from the array s  <  =  >  bali >  = 0 for 1 <  = i < n and baln =  - 1. This can be proved using mathematical induction, the parameter is the number of "int"-s in the array.
And how to find the solution, if we know that is exists? Consider the function gettype(inti), which builds the type beginning in the position i and returns the index, next to the position where it finished building of type. How it works? If si =  "int", then the function prints "int" and returns i + 1. Else it prints "pair < ", gettype(i + 1) is launched, let it returns j. Then we print ", " and launch gettype(j) (it returns k), then we print " > " and return k.
We can not to do check if the type can be reestablished from the array in the beginning: launch gettype() and print "Error occurred" if there became some contradiction during the building of type.

DNon-secret Cypher

First solution: Let's use the method of two pointers. For every number we will know how many times it occurs in the current segment [l, r]. For fixed l we increase r until a[r] occurs in the current segment less than k times. If a[r] occurs int the segment [l, r] k times, we add to the answer all segments [l, t] for all t >  = r and increase l (and do not forget to decrease the number of a[l] in the current segment).
To keep the number of every value in the segment we can use map or compression of the coordinates. Also it's important not to forget that the maximal answer is , which doesn't fit in int.
Second solution: firstly, let's do the compression of the coordinates. For every value X we write the list of the positions i such that a[i] = X. Now using that we fill the array b: b[i] is the minimum index that segment [i, b[i]] contains k numbers equal to a[i] (obviosly, a[b[i]] = a[i]), if this index doesn't exist, then b[i] = n + 1.
Let's find for every index i a minimal index j such that segment [i, j] contsins k equal numbers (if such j doesn't exist, we say that j = n + 1) — then we add to the answer n + 1 - j. This j is equal to . All that minimums can be found in a single pass through a from its end. Then we can sum the answers for all indexes 1 <  = i <  = n.
The complexity of these solutions is O(nlogn).

ECounter Attack

This problem has several different solutions. Anyway, we should consider towns as the vertices of the graph, roads as its edges. Now we are to find the connected components of the complementary graph (CG) of the given graph. Let's take the vertex A with the minimal degree c: . We call the set of the vertices who are connected with AB, that are not connected — D . All vertices which don't connect with A will be in the same connected component of the CG. Let's build the complemented graph to the subgraph including A and set B — there are vertices and  =   =  O(m) edges.
Let's build DSU for the vertices of given graph and merge components which we have found using the new-built graph. All that we should do after it is to consider vertices from B: now we look to the vertex v. We put v in the same component as A if v has edges not to all vertices of D (we do it using DSU too). The complexity of this solution is O(m) or O(mlogn).

Another solution: we keep set a, which contains vertices, which haven't been visited yet. Let's run series of bfs to find the components of CG. If we are working now with the vertex v, pass through a. Consider u is the element of a. If edge (u, v) isn't in the given graph, than u is in the same component of CG as v, so, we can erase it from a and add to queue. Otherwise, we do nothing.
What is the complexity of this solution? To understand that, we must know how many times whe consider fixed vertex u in the set a. u remains int a when we run to them from vertex v  <  =  >  edge (u, v) is in the given graph. So, every vertex u remains in a no more than its degree. So, the complexity of this algorithm is O(mlogn) (log n because of binsearch — we need use it to know, is (u, v) in the graph). If we use HashMap, we'll get O(m).

Full text and comments »

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