Sei sulla pagina 1di 9

Interesting Problems discussed at

Peruvian Training Camp 2015


Joshimar Cordova
jcmonroy9@gmail.com
These problems were discussed during the Peruvian Training Camp that was
held during February. We decided to include only a small subset of the
problems discussed during the first week in this brief document (those that
teach nice algorithmic ideas that may prove useful in other problems). We
assume the reader has carefully read and understood the problems statement
and the input limits. Any suggestions/corrections are appreciated.

Sereja and Squares


Source: Codeforces
Link
A plausible approach is to fix some part of the geometric object we are
looking for, and then count how many objects exist with that fixed part. A
natural guess for this part would be a vertex on the side of the square parallel
to the X axis. Let this point be P1 and lets denote by SY all points in the input
with y coordinate equal to Y; once we have fixed P1 we iterate over all points
P2 in SP1 .y , these two points fix a side of the squares we are counting, so what
remains is to check whether the two other vertices exist: let l = |P1 .x P2 .x|
denote the length of the square we are looking for, we need to check if P3 =
(P1 .x, P1 .y l) and P4 = (P2 .x, P2 .y l)1 are present in the input and this
can easily be done (with a binary search) if we store the input points in an
appropriate data structure. Once we finish processing a set SY we can remove
2
those points from the input. Its clear that for each set SY we spend O(|S
Y | )
time, hence we can afford to perform this only for those sets with |SY | = O( N ),
as otherwise the solution would be too slow.

Now we have to deal with the squares associated with sets of size ( N ):
reflect all remaining
points with respect to the line y = x, now it holds that
all
(before the reflection we only had sets of size ( N )
sets SY have size O( N )
hence we had at most O( N ) such sets (its easy to see this by contradiction),
so all the sets SX associated with points with x coordinate equal to X had
1 Note

that P1 .y = P2 .y since P2 SP1 .y


size O( N )), so we simply apply the same procedure again. IMHO,
its a nice

exercise to prove that this solution has a running time of O(N N lg N ).


These kind of problems are somewhat traditional in programming competitions, consider the following two variants: a) given N points in the integer
plane count how many isosceles rectangle triangles can be formed and b) count
how many isosceles triangles/parallelograms can be formed. These are left as
exercises to the reader.

Ingenious Metro
Source: Live Archive
Link
If the state-space were much smaller we could try to solve this problem
with a Breadth First Search over the implicit graph that is given: the current
position would be the current vertex, and from each vertex T edges would come
out leading to new positions/vertices; all we want to know is whether vertex v
is reachable from u. However, with the given constraints, the size of this graph
is huge, so this is not a feasible approach2 .
Lets focus instead on the formula for the jumps; to quote from the problems
statement if the location of the start station is i and the user presses the key
corresponding to the teletransporter located in position j, he will be taken to
the station located at position 2j i. Lets assume that position j is reachable
from position i through the sequence of teletransporters u1 , , uk , then it must
hold that
2tuk 2tuk1 + 2tuk2 . . . + (1)k+1 2tu1 + (1)k i = j
Lets assume that k is even 3 , the condition can be written as:
2(tuk tuk1 + . . . + tu2 tu1 ) = j i
So, if there is a solution using an even number of teletransporters it must
hold that 2 | j i. The condition becomes
(tuk tuk1 ) + . . . + (tu2 tu1 ) = (j i)/2
The problem now is that theres not a clear relationship between the indices
ui (we only assumed there existed a sequence of such indices that could take
us from position i to position j), lets focus on a single term of the previous
equation, say, (tu2 tu1 ) and WLOG assume that u2 > u1 , then this term can
be rewritten as (tu2 tu2 1 ) + (tu2 1 tu2 2 ) + . . . + (tu1 +1 tu1 ), what we
did here was to express the term (tu2 tu1 ) as a telescoping sum of consecutive
2 But

it is worth considering it, sometimes the size of the state-space is small enough
the parity of k allows us to get rid of the ambiguity of signs at the end of the

3 Fixing

equation

teletransporters and, in fact, all terms of the long equation can be rewritten in
this way so that the condition becomes
Ci Z : CT 1 (tT tT 1 ) + CT 2 (tT 1 tT 2 ) + . . . + C1 (t2 t1 ) = (j i)/2
where the Ci are arbitrary integer constants. What did we gain from doing
all this ? Now we have a diophantine equation and we are only interested in
the existence of a solution. From number theory we know that there exists
a solution (in fact, an infinite number of solutions) if and only if gcd(tT
tT 1 , . . . , t2 t1 ) | (ji)/2, since this condition can easily be checked the problem
is almost solved. We only need to consider the case when k is odd: simply fix any
teletransporter to be tu1 (you have to try with each of the T teletransporters),
then the right hand side of the condition becomes (j + i)/2 2 t with t being
the teletransporter you just fixed, and in the left hand side you are left with the
case of k being even which we just discussed how to solve.
This leads to the final solution with a time complexity of O(T ) to calculate
the gcd4 of the coefficients of our diophantine equation and then O(T ) time per
query.
Traveling Shoemaker Problem
Source: Live Archive
Link
Initially it looks like this problem is about Hamiltonian paths, that is, finding
a path over the graph that visits each vertex exactly once. Unfortunately this
is a NP-complete problem and with the given constraints theres no future to
this approach.
The intended solution, though, uses a similar concept to that of hamiltonian
paths. Each city is associated with at most two colors, say u and v and whenever
we enter a city using color u we exit it using color v (and vice versa). This means
we can treat the cities as edges of a new graph connecting two colors (and the
colors would be our new vertex set). Now the problem becomes that of finding
a path over an undirected graph that visits each edge exactly once; this is called
the Eulerian path problem.
It turns out that eulerian paths are easy to deal with, in fact, we can find
such paths in linear time with respect to the size of the graph, that is, O(V +E).
Note that in this problem we are only interested in the existence of such a path,
and finding the minimum id of a city that can start this path. The following
theorem deals with the existence of such paths:
Theorem 1. An undirected graph G has an eulerian path if and only if G is
connected and at most two vertices have odd degree. In the case that the graph
has two vertices with odd degree the eulerian path must start in one of these
vertices and end at the other.
4 This is not technically correct because the computation of the gcd of two numbers is not
a constant-time operation, see Lam
es theorem

Note that 1) the number of odd-degree vertices in any graph is always even
(this is known as the Handshaking lemma) and 2) if the graph only has evendegree vertices the eulerian path becomes an eulerian cycle (which is of no
consequence for our purposes).
Now that we know how to check the existence of eulerian paths we need to
find the minimum id of a city that can start this path. We can choose any edge
to start the path as long as its removal does not disconnect the graph, that is,
as long as it is not a bridge. We need to handle two special cases: 1) if the graph
has two odd-degree vertices then we only consider the edges connected to these
vertices and 2) we are only allowed to take a bridge if that is the only available
option. In order to check if an edge is a bridge we could proceed by brute force:
remove it and run a BFS (or DFS) and check if the new graph is still connected.
This clearly could detect all bridges in a graph in quadratic time O(E(V + E)).
Theres a much faster algorithm for bridge detection due to R. Tarjan which is
based on an extension of Depth First Search with time complexity O(V +E), but
we wont discuss it here. For a good reference about this algorithm see: https:
//www.udacity.com/course/viewer#!/c-cs215/l-48723544/m-48729232
This concludes the model solution, which has time complexity O(N + C),
assuming a linear-time bridge-detection algorithm is used.

Captain Obvious and the Rabbit-Man


Source: Live Archive
Link
Given p(i) = a1 F1i + a2 F2i + . . . + ak Fki with the ai s unknown and
the k values of p(1), p(2), . . . , p(k) we want to know the value of p(k + 1).
Since we have k unknowns (the ai s) and k equations (given by the values
of p(1), . . . , p(k)) we may be tempted to solve this system of k equations, however, two issues arise: 1) most algorithms to solve linear systems of equations
(such as Gaussian-elimination) have complexity O(k 3 ), where k is the number
of unknowns/equations, in this problem k may be up to 4000 so a complexity of
O(k 3 ) is impractical, and 2) we would need to solve this system modulo M and
we are not guaranteed that M is prime (Gaussian-elimination can be modified
to work over the field Zp when p is prime). Based on these two issues we need
to look for another approach.
p(i) is basically a linear combination of exponentials (where the bases are
the Fibonacci numbers Fi ), and these (combinations of exponentials) arise when
studying the general solutions of linear homogeneous recurrences with constant
coefficients, so lets briefly review this connection. Consider the recurrence
tn+2 = 5tn+1 6tn , which has this characteristic equation x2 5x + 6 = 0
whose roots x1 = 2, x2 = 3 imply that the general solution of tn is given by
tn = a1 2n + a2 3n (and the constants a1 , a2 depend on the base cases associated
with the recurrence). This short discussion is enough to go back to our original
problem: based on the formula for p(i) we know that it came from a linear
recurrence whose characteristic equation is (x F1 ) (x F2 ) . . . (x Fk ) =
4

xk + Ak1 xk1 + . . . + A1 x + A0 . Hence the original recurrence was pn+k +


Ak1 pn+k1 + Ak2 pn+k2 + . . . + A1 pn+1 + A0 pn = 0, setting n = 1 gives
us an equation to compute p(k + 1) using the values of p(1), . . . , p(k) and the
coefficients Ai . These coefficients can easily be calculated by naively multiplying
the terms (x Fi ) in total time O(k 2 ) 5 , which immediately leads to a solution
with complexity O(k 2 ).
Its interesting to note the slightly hidden connection of this problem with linear recurrences. See this problem https://code.google.com/codejam/contest/
32016/dashboard#s=p2 for another nice application of this idea.
Euclidean Nim
Source: Polish Collegiate Programming Contest 2014
Link
Lets first deal with the infinite-game issue. If at some point the game ends
it means there exist constants A, B with Ap + Bq = n, hence if gcd(p, q) - n
the game will go on forever. If gcd(p, q)|n then we can divide n, p, q by gcd(p, q)
and now we can assume that gcd(p, q) = 16 By symmetry we can assume that
p > q, so there are only 4 cases to consider:
1. p starts and p > n. He has to put p stones so we end up with n + p
stones, now the optimal strategy for q is to remove as much as possible
leaving (n + p) mod q < p, restoring the initial condition. Hence q always
ends up with a quantity of the form (n + kp) mod q for some k and since
gcd(p, q) = 1 this quantity will eventually become zero, so in this case q
always wins and p loses.
2. q starts and q n. He leaves n mod q < p stones and now p plays, but
based on the previous case p loses so q also wins in this case.
3. q starts and q > n. He has to put q stones so we end up with n + q
stones. If n + q < p then, by reduction to the first case, p loses so in this
case q wins. If n + q p then player p can only remove p stones leaving
n (p q)7 Hence q loses if and only if p q | n otherwise he wins.
4. p starts and p n. Notice that in this case the only interesting move for
p is to leave n mod p stones. If n mod p q then q wins because of the
second case. Otherwise, using the third case, q loses (and p wins) if and
only if p q | n mod p.
These 4 cases cover all possible developments of the game.
5 Simply represent a polynomial as an array of integers, e.g. x2 5x + 9 is represented
as the array [9, 5, 1]. In order to perform multiplication by (x a) simply shift the array
representation one position to the right to get [0, 9, 5, 1]. Now create a copy of the original
array but with its values multiplied by a, that is, [9a, 5a, a] and finally add the two arrays
position-wise to get [9a, 9 + 5a, 5 a, 1]
6 Note that this trick does not alter the winner of the game nor his strategy.
7 Note that player p cannot remove 2p or more stones.

Largest Submatrix
Source: SPOJ
Link
The minimum criteria that we are asked to maximize in this problem is
monotonic: assume that you can find a valid submatrix (with area at least
K) such that its minimum value is at least p, then this minimum value is
(obviously) at least p 1, and at least p 2, , and at least 0. This simple
observation means we can use a binary search on the minimum-value criteria:
for a fixed p if we are able to find a valid submatrix whose minimum is at least
p we continue the search on the range [p, M AX] (where M AX is the maximum
value of the input matrix), otherwise we continue the search on [0, p 1].
Now our problem is slightly different, we are given a value p and we only
need to check the existence of a submatrix such that all its elements are at least
p (this immediately implies that its minimum value is also at least p) and whose
area is at least K. Lets iterate over the input matrix M and whenever we find
a value less than p we write a 0 in that position and a 1 otherwise. Now we
need to check if there exists a submatrix of area at least k that contains only
1s: simply find the largest submatrix consisting of 1s and check if its area is
at least k.
So now we are left with a final subproblem: given a binary matrix (consisting
of only 0s and 1s) find its largest submatrix consisting of 1s. For a RxC input
matrix there is an well-known O(RC) algorithm for this problem (linear in the
size of the input matrix), which we wont discuss here (a quick google search
should provide relevant descriptions about this algorithm).
In the end, our solution has time complexity O(RC lg M AX).

DZY Loves Fibonacci Numbers


Source: Codeforces
Link
These problems that deal with range queries and updates are usually solved
with segment trees enhanced with lazy propagation. In addition, the particular
update-operations given in this problem are quiet interesting.
We need to define 1) the data we have to store in the nodes of our segment
tree to handle queries and 2) the propagation data we have to store to handle
range updates efficiently. For 1) its easy, for a node u that represents the
Pj
subarray v[i . . . j] we simply store the value Su = k=i vk mod M . Handling 2)
is where things get a little complicated; given a node u associated with v[i . . . j]
we want to do
v[k] = (v[k] + Fki+1 ) mod M, k = i, . . . , j

(1)

. This is where we make use of some basic properties of the Fibonacci numbers.
The base cases of these numbers are 0 and 1, but if we generalize them and
set them to a and b then the new sequence becomes a + b, a + 2b, 2a + 3b,
3a + 5b, 5a + 8b, . . . . Its easy to see that the ith term of the new sequence
is Ti = aFi + bFi+1 , with Fi being the (usual) Fibonacci numbers; hence any
sequence of Fibonacci numbers Fi , Fi+1 , . . . can be succinctly represented by
just a pair of numbers (the base cases) (Fi2 , Fi1 ).
So, to perform the lazy propagation we simply need to store the pair (a, b)
(which initially is going to be (1, 0)). Now we need to know how to propagate
these values to the children of node u, and how to accumulate different pairs of
base cases. Propagating them to the left child is trivial, just pass the same pair
(a, b). The right child case is different; the right child is associated with the
subarray v[k + 1 . . . j] with k = (i + j)/2 and according to equation (1) these
values should be updated by Fkl+2 , Fkl+3 , . . . , Fji+1 which is not the same
initial Fibonacci sequence (this one is shifted by several positions). But, from
the previous paragraph, all we need to store is simply the pair of base cases
(Fkl , Fkl+1 ) and that pair is the one we should propagate to our right child.
How do we accumulate different pairs of base cases ? Say node u (associated
with subarray v[i . . . j]) already stored the pair (a, b) and later on an update
from his parent pushes to him a new pair (a0 , b0 ). The first pair (a, b) was
representing the update given by
v[k] = (v[k] + aFki+1 + bFki+2 ) mod M, k = i, . . . , j
and the second pair (a0 , b0 ) wants to perform the update given by
v[k] = (v[k] + a0 Fki+1 + b0 Fki+2 ) mod M, k = i, . . . , j
both updates turn into
v[k] = (v[k] + (a + a0 )Fki+1 + (b + b0 )Fki+2 ) mod M, k = i, . . . , j
which basically means that the new pair we need to store is simply (a+a0 , b+b0 ).
The final part of the solution is how to refresh the values Su stored in the
nodes of our segment tree with a given pair (a, b)9
Pj
Remember that Su = k=i vk mod M and now we want to incorporate the
Pj
pair (a, b) into this value, so the new value of Su becomes k=i vk + aFki+1 +
Pj
Pj
Pj
bFki+2 = k=i vk + k=i aFki+1 + k=i bFki+2 = SP
u + a(Fji+3 1) +
n
b(Fji+4 2) where in the last step we used the identity k=1 Fi = Fn+2 1
(which can easily be proved by induction on n). This means we can incorporate
the pair (a, b) into the value of Su in constant time. Answering queries is a
8 The purpose of using lazy propagation here is to avoid a complexity of O(n) to handle
these updates
9 This is where the actual update operation is performed. The lazy propagation trick allows
us to delay this as much as possible (we stop at nodes that are fully contained in the range
update) but when we perform queries we need to update the values, and possibly, propagate
the pairs (a, b) towards the children as already explained.

straightforward procedure (simply add the values Su for all nodes u that are
contained in the range query).
If the reader is not familiar with segment trees nor with lazy propagation,
the problem LITE (http://www.spoj.com/problems/LITE/) is a good introductory problem on this topic.
Its worth mentioning that this problem can also be solved using the Binary
Indexed Tree aka Fenwick Tree.

Matrix
Source: SPOJ
Link
Let A denote the input matrix. There are O(M 2 N 2 ) submatrices so we
cannot simply check them one by one. We will perform a standard reduction
of this problem to the 1D case: fix the upper and lower boundaries of the
submatrices we are looking for at positions i and j respectively (this means
the submatrices we are focusing on start somewhere on the i-th row and end
somewhere on the j-th row). Lets build an array v[1 . . . M ] such that v[k] =
Pj
l=i A[k][l], k [1 . . . M ], then its easy to see that were looking for subarrays
v[l . . . r] of v such that the sum of its elements is in the range [A, B]. Note that
there are O(N 2 ) ways of fixing the positions i and j (simply try all possible
pairs); if we were able to solve the new 1D subproblem in time O(t(M )) then we
would have a final complexity of O(N 2 t(m)) so we need to have t(m) = o(M 2 )
(we should aim at O(M lg M ) or better).
Lets now focus on the 1D subproblem. Given an array v of M integers in
the range [109 , 109 ] count the number of its subarrays whose sum of elements
is in the range [A, B]. We briefly describe a well-known O(M lg M ) solution
based on Fenwick Trees: for aP
fixed position j we want to count the number
of positionsPi < j with A
i<kj vk B, lets introduce prefix sums pi
with pi = ki vk and p0 = 0, then the previous condition can be rewritten
as A pj pi B pj B pi pj A, hence for a fixed j we want to
count the number of positions i with pi in the range [pj B, pj A]. This can
be done using a Fenwick Tree as follows: map the integers pi into the range
[0, M ] (simply sort them in O(M lg M ) and assign them their ranks) and lets
keep an array of frequencies fi that counts the number of times we have seen
the (mapped) number i. For a fixed j we need to count the number of positions
i with rank(pi ) in the range [rank(pj B), rank(pj A)] and this is simply
Prank(pj A)
fi which can be computed in O(lg M ) using a Fenwick Tree.
k=rank(pj B)
Once we are done with a fixed j we move to j + 1 and simply update frank(pj )
by one, which can also be done in O(lg M ) using the same data structure. This
concludes the solution with time complexity O(N 2 M lg M )
The key ideas in this problem were the reduction to a 1D simplification of
the problem and the subproblem of counting subarrays whose sum lies in a given
range.

Petrol
Source: Polish Collegiate Programming Contest 2014
Link
In these kind of problems its a good idea to build a new graph where the
solution we are looking for (obviously) changes but its now easier to find. For
each node u lets denote with du the shortest distance from u to a petrol station.
These values can be computed with a single execution of Dijkstras algorithm
in O(m lg n) time 10 . Now build a new graph G0 containing the same vertices
as the original graph and the same edges, but with modified weights: for each
edge (u, v) set its new weight w0 (u, v) equal to du + w(u, v) + dv where w(u, v)
denotes its original weight. Then it holds that its possible to go from x to y
using a tank with capacity b in the original graph if and only if you can go from
x to y in the new graph using only edges with weights w0 (u, v) b; the proof
of this fact is left as a nice exercise to the reader.
Now we have a potential approach for a solution: for each query consisting
of the integers x, y, b remove from the graph G0 all edges with w0 (u, v) > b and
check if nodes x and y are connected using a BFS or DFS. This leads to a total
complexity of O(q(n + m)) to answer all q queries, which clearly will be too slow
given the limits of this problem.
The final idea to reduce the time complexity is to use offline query processing.
This means that instead of answering queries as they come (aka online processing) we save them all and reorder them in a more convenient way that facilitates
the processing. Here this order is quiet intuitive: we save all queries (which are
triplets (x, y, b)) and sort them in non-decreasing order of the b value. When
we want to solve a query with value b we work with all edges with w0 (u, v) b.
When we move on to another query with b0 > b theres no need to waste all the
previous work we did when solving for b, we simply need to incorporate edges
with w0 (u, v) b0 and check if x0 and y 0 are in the same connected component.
Since we need to constantly add edges to a graph and check if two nodes are in
the same component we can use the union-find data structure of R. Tarjan for
this purpose, and the problem is now completely solved.
The idea of creating new graphs to transform the solution space is very
common. In addition, offline processing is a powerful tool that eases the solution of many problems that would otherwise require complicated online data
structures, see this problem http://www.spoj.com/problems/DQUERY/ for an
excellent exercise using offline techniques.

10 During the initialization stage of Dijkstras algorithm, simply push all nodes that are
petrol stations into the heap with distance 0, then proceed as usual.

Potrebbero piacerti anche