Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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
size O( N )), so we simply apply the same procedure again. IMHO,
its a nice
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.
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).
(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.