Tutorials
Tutorials
Tutorials
Problem A. LaIS
Let’s add 0 to the beginning of a, then we’ll increase LaIS by one and so it will always start from 0. Let’s
look at any almost increasing subsequence (aIS) and underline elements, which are minimums in at least
one consecutive pair, for example, [0, 1, 2, 7, 2, 2, 3].
Note that underlined elements form increasing subsequence (IS) and there is no more than
one element between each consecutive pair. What constraints these elements have? Obviously,
a[posi−1 ] ≤ a[posi ] ≥ a[posi+1 ], but we can ease the constraints just to a[posi−1 ] ≤ a[posi ], i. e. we
can allow a[posi ] < a[posi+1 ], since aIS will still be aIS.
Now, note that between posi−1 and posi+1 we can choose any j such that a[posi−1 ] ≤ a[j], so we can
always choose the first such j, moreover we can precalculate such j as nxti for each ai . Using stacks or
something similar.
Now, we can note that each ai is either minimum in LaIS or i = nxtj for some other element aj . And
we can write the following dynamic programming: let d[i] be the LaIS which finish in ai and it’s the last
minimum (we can think that the last element of LaIS is minimum in the imaginary pair). To calculate it,
we can iterate i from left to right and store for each value x the length of LaIS with the last minimum
(not the last element) equal to x in Segment Tree (ST).
So, di is equal to “get maximum over segment [0, ai ] in ST” plus 1. And we update ST in two moments:
firstly, right now with value di in position ai and secondly, after we meet the element nxti with value
di + 1 also in position ai .
After we process all i we’ll get ST where for each x the length of LaIS with last minimum equal to x will
be stored and the answer will be equal just to “maximum over all tree (segment [0, n])”.
In total, we should calculate nxti for each ai (we can do it in linear time using stack) and maintain
Segment Tree with two basic operations: range maximum and update in position. The time complexity is
O(n log(n)) and the space complexity is O(n).
Problem B. Bakery
Let’s look at all n days with some fixed k. Obviously, the seller works like a stack, so let’s divide all days
into segments in such a way, that the stack is emptied between consecutive segments. We can note that
after we’ve got these segments — the answer is the maximum length among all segments. Why? Because
the stalest bread on the bottom of the stack and we can’t sell it until we empty the stack.
Now, let’s set k = 109 and look at what happens when we gradually lower k. With k = 109 , we sell all
bread that we baked on the same day, so all segments consist of one day [i, i + 1). Now, if we start lowering
k then at some moment segments will start to merge (and only merge), since k is not enough to sell all
bread in this interval. Since no segment will split up, there will be only n − 1 merging.
So we can look only at moments k when either several segments merge or when we should answer the
query. With what k the segment [p1 , p1 )jwill
P
startk to merge with the next segment [p1 , p2 )? The answer
P ( ai )−1
is when (p2 − p1 ) · k < ai or k = p2 −p1 .
p1 ≤i<p2
So, we can for each segment [pi , pi+1 ) maintain its value ki when it will start merging with next segment in
set. And if we want to calculate the answer for a given k from the queries, we should merge all segments
with ki ≥ k, while updating the current maximum length among all segments.
Since merging two segments require two operations with the set then the total time complexity is
O(m + n log n).
Problem C. Berpizza
The hardest part of this problem is to efficiently implement the third query, i. e. finding the customer
with the greatest value of m and erasing it. Simply iterating on all of them is too slow, since there may
be up to 2.5 · 105 such queries and up to 5 · 105 customers at the pizzeria.
Page 1 of 7
2020-2021 ICPC, Northern Eurasia, Southern and Volga Russian Regional Contest
Russia, Saratov, November, 15, 2020
There are several solutions to this issue, I will describe two of them. The first solution is to treat each
customer as a pair (id, m), where id is the number of the customer. Then the first query means “insert a
new pair”, the second query — “remove the pair with minimum id”, and the third query — “remove the
pair with maximum m”. To maintain them, we can use two balanced binary trees that store these pairs
— one will store them sorted by id, and the other — sorted by m. Then the second query means “find
the leftmost element in the first tree and erase it from both trees”, and the third query means “find the
rightmost element in the second tree and erase it from both trees”. Balanced binary trees can perform
these operations in O(log n), where n is the size of the tree. Note that in most languages you don’t have to
write a balanced binary tree from scratch — for example, the containers std::set in C++ and TreeSet
in Java already support all of the required operations.
The second solution maintains three data structures: a queue for supporting the queries of type 2, a heap
for supporting the queries of type 3, and an array or set that allows checking whether some customer was
already deleted by a query. Finding the customer that came first using a queue or has a maximum value
of m using a heap is easy, but deleting some element from queue/heap is much harder (because we have
to delete some arbitrary element, not necessarily the element at the head of the queue/heap). Instead,
we can do it the other way: when we delete some customer from one of these data structures, we mark
it as deleted. And while processing the following queries of type 2 or 3, we should check the element in
the head of the data structure and, if it is marked as deleted, remove it before processing the query. Note
that there can be multiple such elements, so it should be done in a loop. Since each element is deleted at
most once, this solution works in O(n log n) amortized.
Problem D. Firecrackers
The first crucial observation that we need is the following one: it is optimal to light and drop some
firecrackers, and only then start running away from the guard (that’s because running away doesn’t
actually do anything if none of the firecrackers are lit). The hooligan shouldn’t drop more than |a − b| − 1
firecrackers, because otherwise he will be caught before starting running away, and the last firecracker he
dropped won’t go off.
Okay, now suppose the hooligan wants to explode exactly f firecrackers. It’s obvious that he wants to
choose the f firecrackers with minimum si , but in which order he should drop them? If the i-th firecracker
he drops goes off in sj seconds, then it will explode on the (i + sj )-th second. We have to choose an
ordering of the firecrackers that minimizes the maximum of (i + sj ) in order to check that the hooligan
has enough time to see all the firecrackers he dropped explode. It can be shown that we can drop the
firecracker with the maximum sj first, then the firecracker with the second maximum sj , and so on, and
the maximum of (i + sj ) is minimized (obviously, we consider only the firecrackers with f minimum values
of si ).
This leads us to a solution with a binary search on f in O(n log n): we can check that the hooligan
can explode at least f firecrackers in O(n) (after sorting the sequence s beforehand), and binary search
requires to check it for only log n values of f .
Page 2 of 7
2020-2021 ICPC, Northern Eurasia, Southern and Volga Russian Regional Contest
Russia, Saratov, November, 15, 2020
• from (a1 , 0) to (a1 , a4 ).
So, the solution is to sort the sequence [a1 , a2 , a3 , a4 ], and then print a1 · a3 .
Problem G. Hobbits
Let’s start with the general idea of the solution. To solve the problem, we need to iterate over all relief
segments and understand, which part the segment is seen by the Eye. A segment point can be hidden from
the Eye by several mountains, but it is enough to track only the highest mountain. Generally speaking,
the relief segments can be processed in any order, bit it would be more convenient to iterate on them
backwards — i.e. in the order from the Eye to the start point. Processing the segments in reversed order
will allow to recalculate the highest mountain easier.
Let’s now discuss implementation details. Formally speaking, there are n relief points pi = (xi , yi )
(1 ≤ i ≤ n) and the Eye point E = (xn , yn + H). Each relief point defines its own angle αi , which
is measured counter-clockwise between positive direction of the OX axis and the (E, pi ) vector. Now,
having two relief points pi and pj (i < j), it can be said that pi is hidden from the Eye if αi > αj . When
this check is implemented in the solution, to avoid the precision loss, it is recommended to use vector
product and analyse its sign to understand the relation of the angles. This check is done in O(1) time.
Being able to understand when a point is hidden from the Eye by another point, it is possible to calculate,
which part of a segment (pi , pi+1 ) is seen by the Eye. First of all let’s note, that if the segment left point
pi is hidden by its right point pi+1 , then the entire segment is hidden from the Eye. Now, we have the
situation when left segment point is not hidden from the Eye by its right point. But the segment or its
part can still be hidden by the highest mountain (point M ), which is a point with minimal angle from all
relief points, located to the right of our segment. Here three cases are possible:
Page 3 of 7
2020-2021 ICPC, Northern Eurasia, Southern and Volga Russian Regional Contest
Russia, Saratov, November, 15, 2020
• both pi and pi+1 are hidden by M — in this case the entire segment is hidden and we switch to the
next segment;
• both pi and pi+1 are visible by the Eye (not hidden by the highest mountain M ) — in this case the
entire segment is visible and we should add its length to the answer;
• left segment point pi is visible by the Eye, but right segment point pi+1 is hidden by M — in this
case we need to find intersection point I of the segment (pi , pi+1 ) and the ray (E, M ). What is left
- add length of (pi , I) segment to the answer.
It is very convenient to implement segment and ray intersection in a parametric way, when intersection
point I is represented as I = pi + t1 ∗ (pi+1 − pi ) = E + t2 ∗ (M − E) and then parameters t1 and t2 are
found as solutions of linear equation system.
Now, let’s conclude the final algorithm:
1. Iterate over all relief segments from right to left, keeping the highest mountain point M .
2. Analyze how left and right points of the current segment are located relatively to each other and
point M .
3. Recalculate M , taking points of the current segments as candidates for the highest mountain.
Page 4 of 7
2020-2021 ICPC, Northern Eurasia, Southern and Volga Russian Regional Contest
Russia, Saratov, November, 15, 2020
Page 5 of 7
2020-2021 ICPC, Northern Eurasia, Southern and Volga Russian Regional Contest
Russia, Saratov, November, 15, 2020
maximum speed limit less than k, not exactly k. We have to choose a road with the current speed limit
as close to k as possible, i. e. the one with the minimum value of |si − k|. After applying |si − k| changes
to it, we can choose n − 2 roads having si ≤ k to form a spanning tree with the chosen road (it is always
possible due to the properties of the spanning tree: if we have a spanning tree and we want to add an edge
m
of the graph to it, we can always find another edge to discard). So, in this case, the answer is min |si − k|.
i=1
Page 6 of 7
2020-2021 ICPC, Northern Eurasia, Southern and Volga Russian Regional Contest
Russia, Saratov, November, 15, 2020
set flag w[x]=1. Now for each other set T with size k we may calculate amount of integers x in T that
satisfy condition w[x]=1 (i.e. amount of common integers with S) using O(k) operations. So, we will use
O(m) operations for each large set S. Since D=m1/2 we will have at most m/D = D large sets and will
perform O(D ∗ m) = O(m3/2 ) operations.
Now we have to check whether there are two similar small sets. For each small set S let’s find all pairs
of integers (x, y), x < y in this set. If there are two equal pairs in different sets, that sets are similar.
To find such pairs we may just create a separate array for each integer x and add all values y to it. It is
possible to check whether there are two equal integers in array in O(k) operations, where k is the size of
this array. Since the size of each small set is at most D we will have at most D ∗ k pairs for each set of
size k and at most D ∗ m pairs in total. So we will perform O(D ∗ m) = O(m3/2 ) operations.
Page 7 of 7