You are on page 1of 21

SRM: 351

InsertSort:
Used as: Division Two - Level Three:
First, let's reinterpret the problem. During the move operation described in the problem statement we
will erase the taken number but will not put it back into the array. We will continue such operations
until the remaining array is sorted. It is quite evident that these two problems are equivalent.

Accordingly, with the new problem interpretation we should find the non-decreasing subsequence with
the maximal sum of its element. After that erase all elements that are not in the subsequence using the
modified move operation. And this will be the optimal sort.

We can find the non decreasing subsequence with the maximal sum of its element using dynamic
programming. Let A[n] be a maximal sum of elements of non decreasing subsequence in the case if n is a
last taken element. A[n] could be calculated with the following formula:

A[n] = Max(A[i], (i < n) and (theArray[i]<=theArray[n])) + theArray[n];


The answer for the initial problem will be the sum of all elements in theArray minus the maximum
element in the array A.

Here is I-I's solution that illustrates this idea:


public int calcMinimalCost(int[] theArray)
{
int[] f = new int[theArray.Length];
int res = 0;
for (int i = 0; i < theArray.Length; i++)
{
f[i] = theArray[i];
for (int j = 0; j < i; j++)
{
if (theArray[j] <= theArray[i]) f[i] = Math.Max(f[i], f[j] + theArray[i]);
}
res = Math.Max(res, f[i]);
}
res = -res;
for (int i = 0; i < theArray.Length; i++) res += theArray[i];
return res;
}

BoxesArrangement
Used as: Division One - Level Two:
This problem can be solved with dynamic programming. Let's D[NA][NB] [NC][Q][K] will be a maximal
number of never moved boxed in the final configuration, if the first NA+ NB+ NC boxes contain NA 'A'
boxes, NB 'B' boxes and NC 'C' boxes, the box with the index NA+ NB+ NC-1 has Q color and there are K-
1 boxes of the same color being exactly before it.
If we have value for D[NA][NB][NC][Q][K] there are three variants for the box with the index NA+ NB+
NC. They can be either 'A', or 'B' or 'C'. By adding up each of these boxes we will get value for the longer
prefix of the boxes. Iterating this process we will find the answer for the problem.

int memo[51][51][51][4][3];

int inf = 1000000;

VI v;
int cnt[3];
int doit(int a,int b,int c, int prev, int l)
{
if(l == 3) return -inf;
if(a > cnt[0] || b > cnt[1] || c > cnt[2]) return -inf;
int n = a + b + c;
if(n == v.size()) return 0;
int & ret = memo[a][b][c][prev+1][l];

if(ret != -1) return ret;


ret = -inf;
fo(i,3){
ret >?= (v[n] == i) + doit(a+(i==0),b+(i==1),c+(i==2), i, (i==prev)?(l+1):(1));
}
return ret;
}

class BoxesArrangement{
public:
int maxUntouched(string boxes) {
fo(i,boxes.size()) v.pb(boxes[i]-'A');
fo(i,v.size()) cnt[v[i]]++;
memset(memo,-1,sizeof(memo));
int ret = doit(0,0,0,-1,0);
if(ret >= 0) return ret;
return -1;
}

};

SRM: 352
NumberofFiboCalls
Used as: Division Two - Level Two:
Usually a Fibonacci numbers example is used in computer science lectures to illustrate the
principles of dynamic programming. Exponentially slow algorithms become sufficiently fast by
inserting a few lines of code. In this problem we should do the same with two element vectors
instead of numbers.

Let F[i][0] and F[i][1] be the number of times '0' and '1', respectively, will be printed during a
fibonacci(i) call. Then

F[0][0] = 1; F[0][1] = 0;
F[1][0] = 0; F[1][1] = 1;
For i greater than 1: F[i][0] = F[i-1][0] + F[i-2][0]; F[i][1] = F[i-1][1] + F[i-2][1];
The answer is F[n][0] and F[n][1]. F values can be calculated either by forward dynamic
programming (calculate F[i] using known F[i-1] and F[i-2]) or by lazy evaluations with
memorization (do not calculate F[i] in recursive function if it was calculated before, just take it
from the cache). Here is JongMan's code which uses the second (lazy evaluations) approach:
vector<int> cache[41];

vector <int> fiboCallsMade(int n)


{
if(cache[n].size()) return cache[n];
vector<int>& ret = cache[n];
ret.resize(2);
if(n == 0) ret[0] = 1;
else if(n == 1) ret[1] = 1;
else
{
vector<int> a = fiboCallsMade(n-1);
vector<int> b = fiboCallsMade(n-2);
ret[0] = a[0] + b[0];
ret[1] = a[1] + b[1];
}
return ret;
}

RaceManagement
Used as: Division Two - Level Three:

First we will calculate the expected earnings of the company. The company can lose money if
some horse wins outright, and it can earn money in all other cases. Let S be the sum of all
amounts, P[i] be the probability that the i-th horse wins outright and W[i] be the earnings of the
company in case that i-th horse wins outright. The fact that the i-th horse wins the race outright
means that this horse wins and all others lose. So, the probability P[i] equals to the product of
shares of all horses: probability[i] for the i-th horse and (100%-probability[j]) for all other
horses. The value W[i] equals to (S - amounts[i]) - amounts[i]* payload_factor.

Therefore, the expected company's earnings can be calculated by the following formula:

expected_earnings = (100% - sum(all P[i]))*S - sum(all products P[i]*W[i])


To solve the problem we should solve the inequality "expected_earnings = minimumMoney"
with the only unknown variable - payload_factor.

Note that in this problem the maximal number of horses is 5. This fact allows us to write the
solution without using a double type and to avoid precision issues. Here is Java sample code
without using float point operations:
public double getPayoutFactor(int[] probability, int[] amounts, int minimumMoney) {
long sum = 0;
for (int amount : amounts) {
sum += amount;
}
long minm = minimumMoney; //long type variable for minimumMoney
long p=1;
for (int amount : amounts) {
p*=100;
minm *= 100;
}
long win = 0;
long payloadFactor = 0;
for(int i=0; i<amounts.length; i++) {
long cur = 1;
for(int j = 0; j<amounts.length; j++)
cur *= i == j? probability[j] : 100 - probability[j];
payloadFactor += cur * amounts[i];
win += (sum - amounts[i]) * cur;
p-= cur;
}

win += sum * p;

if (payloadFactor == 0) {
if (win - minm >=0) return -2;
else return -1;
}

if (win - minm < 0) return -1;

return (double)(win - minm) / payloadFactor; }


FibonacciKnapsack
Used as: Division One - Level Two:

The key to this problem is the fact that the weight of the item can take on only a few distinct
values. And it is important that these values increase exponentially. This condition allows us to
put forward the bold idea: "If we dismiss an item with a big weight the released space can hold
a lot of smaller items." This idea is not a strict proof of a solution but it is good enough to
understand the main process.

Let's represent the C value into the Fibonaccimal system (it is also called as Zeckendorf
Representation). This action gives us the array C0, C1, ..., CM where each Ci represents how
many Fibonacci numbers Fi we have (initially 0 or 1). Let's consider the maximal Ci that is
greater than 0. We can take from 0 to Ci items with the weight Fi. If we take less than Ci such
items, we transform the remaining Fibonacci numbers into Ci-1 and Ci-2.

More formally, let's A[i][Ci][Ci-1] be a maximal cost that could be taken by items with weight
greater than Fi in such way, that all Cj with j > i are equal to zero, Ci and Ci-1 have
corresponding values and all Cj with j < i - 1 remain as in the initial Zeckendorf Representation.
Choosing how many items with weight equal to Fi are taken, we can update next values of the
A.

Note, that if Ci is not less than number of remained items, we can easily take all of them. This
optimization gives no more than M*N*N (M - index of largest Fibonacci number in C's
Zeckendorf Representation, N - number of items) distinct indexes for the array A.

This wandering around Zeckendorf Representation and many-dimensional dynamic


programming is, of course, very interesting, but, in fact, is not necessary at all. You can take a
look at halyavin's solution. He has implemented simple memorization with the optimization
that if we have enough space to take all remained items we should get them all. Our preceding
matting shows that this solution will be fast enough as well.

SRM: 353
Glossary
Used as: Division Two - Level Two:
Used as: Division One - Level One:

This problem required a clean implementation of the described simple and straightforward
logic. However, a significant amount of coders failed to provide a working solution. Most failed
submissions were in times larger than the fastest (and prettiest) code by bmerry. So never
forget about the KISS principle while competing in TopCoder SRM's.

First we need to sort items in a case-insensitive way, and then fill two columns: the first column
with items whose first letter is from 'A' to 'M', and the second column with items from 'N' to 'Z'.
We can now fill those two columns separately, and after completion we will merge them into
one column of strings - resulting glossary.

To fill one column with words we just push them one after another, and if the first letter
changes we also push a "letter-header" to column. Don't forget to provide a letter-header for
the first word in the column.

To easily merge two columns with different number of elements, we simply add empty strings
(strings of 19 spaces) to the smaller column. When the heights are equal, merging is a trivial
thing.

PlatformJumper
Used as: Division Two - Level Three:
Used as: Division One - Level Two:

Obviously, each journey in the problem is directed downward. That implies each journey has
finite length, and each platform can be visited at most once. So, we can employ dynamic
programming to solve this problem. Let's introduce function F[v] - the maximal number of
collected coins, among all journeys ending at v platform.

If we can calculate that set of platforms S[v], such that platform v can be reached by one jump
from every platform from S[v], then F[v] can be easily computed as a maximum:
F[v] = coins[v] + max{y from S[v]} F[y]

Where coins[v] is number of coins at platform v.

The trickiest part of the problem was to verify if we can jump from one platform to another.
This required knowledge of high school physics. Let's consider two platforms with coordinates
(x1,y1) and (x2,y2), y1>y2. Jumper need to cover abs(x1-x2) distance in Ox direction and (y1-y2)
in Oy direction. Suppose, that we move with highest possible speed in Ox direction - Vmax.
Then we need time Tneed = abs(x1-x2)/Vmax to complete jump. However, when flying we are
moving downward by force of gravity. We can calculate length of path in Oy direction in time
Tneed: Dy = g*Tneed^2/2. If Dy is greater than (y1-y2) obviously we can't perform such a jump.

Most failed submissions incorrectly checked whether we can jump from one platform to
another.

zhuzeyuan's solution clearly follows these ideas:


int maxCoins(vector <string> ss, int v, int g)
{
int i,j,k;
n = ss.size();
for (i=0; i<n; i++)
sscanf(ss[i].c_str(),"%d %d %d",&cc[i].x, &cc[i].y, &cc[i].c);

sort(cc, cc+n); // sorting in order of increasing height

int opt[60], ans = 0;


for (i=n-1; i>=0; i--)
{
opt[i] = cc[i].c;
for (j=i+1; j<n; j++)
if ( opt[j]+cc[i].c>opt[i] &&
(long long) (cc[i].x-cc[j].x)* (cc[i].x-cc[j].x)*g <=
(long long)(cc[j].y-cc[i].y)*2*v*v )
opt[i] = opt[j]+cc[i].c;
if (opt[i]>ans) ans = opt[i];
}
return ans;
}

SRM: 354
DateFormat
Used as: Division Two - Level Two:
Used as: Division One - Level One:

This problem seemed more difficult than the usual Division 1 Easy or Division 2 Medium
problem but, in fact, it didn't require a lot of effort to solve. The greedy works and the only
nontrivial thing lies in the checking which valid dates can be obtained from the given date.

Let's consider the date "XX/YY" is given in the input. We should check "XX/YY" and "YY/XX"
dates for it. The date "AA/BB" is a valid date in the US format if and only if AA is not greater
than 12. This fact ensues from the constraint that each date in the input is a valid date in either
US format or European format.

The entire algorithm for the problem is as follows: Generate all possible dates from the first
date and choose the smallest one. For each subsequent date generate all possible dates from it,
and chose the smallest one that is greater than the preceding. You can use bmerry's solution as
the reference.

UnsealTheSafe
Used as: Division Two - Level Three:

This problem was a classical illustration of dynamic programming problems. The last digit of the
password depends on the preceding digit only. So we can accumulate all passwords of length N
ending with a digit D into one object and work with such accumulated objects.
More formally, let A[N][D] be the number of passwords of length N with a digit D on the end.
Then A[N][D] equals the sum of such A[N-1][X] for whichever digits D and X are adjacent.

Here is LiveInSeoul's solution, which illustrates this idea:

long long countPasswords(int N){


long long d[50][20];
int i;
for(i=0; i<=9; i++){
d[1][i]=1;
}
for(i=2; i<=N; i++){
d[i][0]=d[i-1][7];
d[i][1]=d[i-1][2]+d[i-1][4];
d[i][2]=d[i-1][1]+d[i-1][3]+d[i-1][5];
d[i][3]=d[i-1][2]+d[i-1][6];
d[i][4]=d[i-1][1]+d[i-1][5]+d[i-1][7];
d[i][5]=d[i-1][2]+d[i-1][4]+d[i-1][6]+d[i-1][8];
d[i][6]=d[i-1][3]+d[i-1][5]+d[i-1][9];
d[i][7]=d[i-1][4]+d[i-1][8]+d[i-1][0];
d[i][8]=d[i-1][5]+d[i-1][7]+d[i-1][9];
d[i][9]=d[i-1][6]+d[i-1][8];
d[i][0]=d[i-1][7];
}
long long ans=0;
for(i=0; i<=9; i++){
ans+=d[N][i];
}
return ans;
}

RemissiveSwaps
Used as: Division One - Level Two:

"For every problem, there is a solution that is simple, neat, and wrong." - H. L. Mencken

Initially this problem had a greater upper limit for N. But the "57246" test broke down all the
author's approaches and he was forced to reduce limits. The correct answer for the "57246"
test is "65410" because we can do the following sequence of swaps: 57246 -> 57316 -> 27416 -
> 61416 -> 65410. How to obtain such a result using some 'clever' algorithm? I don't know, in
spite of several days of thinking. If you have an idea, you are welcome to post it on TopCoder's
forum.
With the reduced constraints the problem can be solved with graph theory and any search
algorithm. Another possible solution is a brute force with any reasonable optimization. In this
editorial we will describe the first approach.

Let's build a graph where vertexes are the numbers from 0 to 1,000,000. Let's create an edge
from vertex A to vertex B if the number B can be obtained from the number A by the one swap
operation. The answer is the maximal number that is reached from the vertex N. Here is the
Petr's solution that uses Breadth-first search algorithm for the graph bypassing.

public int findMaximum(int N) {


bool[] reachable = new bool[12000000];
List<int> queue = new List<int>();
reachable[N] = true;
int res = N;
queue.Add(N);
while (queue.Count > 0)
{
int cur = queue[queue.Count - 1];
queue.RemoveAt(queue.Count - 1);
for (int p10 = 1; p10 <= cur; p10 *= 10)
for (int q10 = 1; q10 < p10; q10 *= 10)
{
int dp = (cur / p10) % 10;
int dq = (cur / q10) % 10;
if (dp > 0 && dq > 0)
{
int next = cur - dp * p10 - dq * q10 + (dp - 1) * q10 + (dq - 1) * p10;
if (!reachable[next])
{
reachable[next] = true;
res = Math.Max(res, next);
queue.Add(next);
}
}
}
}
return res;
}

SRM: 355
MixingLiquids
Used as: Division Two - Level Three:
Used as: Division One - Level One:

Consider i-th bottle. It contains amount[i] liters of percent[i]-% liquid, which means
amount[i]*percent[i]/100 liters of substance and amount[i]*(100-percent[i])/100 liters of
water.

Suppose we pour together all the bottles we have. We can calculate the total amount of
substance and water we have by summing the above expressions; let these amounts be
totalSubstance and totalWater. To avoid division, we can calculate them in centiliters (1/100 of
a liter). Having done that, we find the concentration (percentage) of the solution as
totalSubstance/(totalWater+totalSubstance). We need that number to be need/100. If it is,
we're done — the answer is just the sum of all amounts.

In the other case, it is either more or less than required; suppose it's more. Then we need to
somehow reduce the 'substance' part of our mix. It is clear that to achieve that faster we need
to remove the bottle with the highest available percentage of the substance. If that is not
enough, remove the bottle with the next highest percentage, and so on until we get the
required percentage. In most of the cases, however, we will at some point 'jump over' the
required percentage, which means that we need to take the last removed bottle partially.

The only remaining question is how to calculate how much of that bottle we should take. At the
first glance the most obvious way seems to be binary search. However, let's examine the
situation more carefully. Suppose all the remaining bottles have a liters of substance and b
liters of water, and the last removed bottle had c liters of substance and d liters of water. We
need to find such x that (a+x*c)/(a+b+x*(c+d))=need/100. x denotes the fraction of that bottle
we should take. Getting rid of the division, we get (a+x*c)*100=(a+b+x*(c+d))*need — but
that's a simple linear equation on x, so we can solve it easily and obtain the answer.

If the 'full mix's percentage is less than need, we do the same thing, but start with the bottles
with the lowest percentage instead of the highest.

A similar approach was implemented by Andrew_Lazarev.

Tetrahedron
Used as: Division One - Level Two:

Spatial geometry... Is it usually tough? Yes. Is this problem that tough? No! Strangely enough,
this problem allows an almost planar solution.

Let's name our vertices A, B, C and D. At the first step, we check if triangles ABC and ABD are
possible — that is, the triangle inequality holds for them: AB+BC>=AC, AB+AC>=BC, AC+BC>=AB,
AB+BD>=AD, AB+AD>=BD, AD+BD>=AB. If at least one of the above doesn't hold, the answer is
surely "NO".
In case they do, imagine the segment AB fixed in space, and triangles ABC and ABD rotating
around it. What is the maximal and minimal possible value for CD, then? It is logical that the
minimal possible value is achieved when they are in the same plane and 'co-aligned' — that is,
points C and D are in the same semiplane with respect to AB, and the maximal possible value is
achieved when they are in the same plane but 'counter-aligned' (one can prove this by applying
the Pythagoras' theorem, I will omit the formulas, and just note that if AB is along the Ox axis,
then rotating the triangles around it keeps the x-coordinates of C and D the same, thus the
question is again reduced to a planar question in the Oyz plane).

To calculate that bounds, we need to find the possible coordinates of C and D in that plane.
Suppose A has coordinates (0,0), B is at (b,0), and C is at (x,y). To find x, we apply the law of
cosines: x=AC*cos(A), and cos(A)=(AC2+AB2-BC2)/(2*AC*AB). Then we find y with the help of
Pythagoras. Finding the coordinates of D is done similarly, and then we just need to compute
the required distances and check CD against them.

See Egor's code for a simple implementation of this approach.

rahulgarg123 used a different approach not requiring any floating-point computations. The
formula given at this page allows us to find the squared volume of a tetrahedron given its six
sides. It turns out that substituting impossible lengths of sides into that formula yields a
negative value for that square, and that fact was employed in rahulgarg123's code.

SRM: 356
AverageProblem
Used as: Division Two - Level Two:

Used as: Division One - Level One:

Consider some mark m. Let's denote its real value by r (i.e. m is the result of truncation r's
decimal notation as it was described in the problem statement). r can be represented as a
rational fraction, r = p/q. Here q is the number of the participants of the survey, and p is an
integer in range from 0 to 10q.

The key observation is the following inequality: m = p/q < m+0.001. In other words, 1000mq =
1000p < (1000m+1)q.

Now we are going to fix some q and to check if there exists such p, that satisfies the inequality
above. To avoid problems with precision, let's get rid of real-valued numbers: 1000m is always
an integer in range from 0 to 10000, we'll denote it by n (The easiest way is just to remove all
dots ('.') from the input and parse marks as integers.).

The inequality now will look as: nq = 1000p < (n+1)q.


It's easy to see that the required p exists if and only if interval [nq; (n+1)q) (left bound inclusive,
right - not) contains an integer that is divisible by 1000. Note, that if q = 1000, such p always
exists. In this case we need to check only denominators in the range from 1 to 999.

How to check if given interval [a, b) contains an integer, divisible by 1000? We need to check
only two integers: ([a/1000])*1000 and ([a/1000] + 1)*1000. If one of them belongs to interval
[a, b) the answer is yes, and no otherwise.

RoadReconstruction
Used as: Division Two - Level Three:

This problem can be solved by modification of standard Kruskal algorithm of finding MST
(minimal spanning tree) in undirected graph. Cities will be the vertice of that graph, and roads
will be its edges. Each damaged road will provide the corresponding edge the weight that
equals the cost of the reconstruction. Other (non-damaged) roads will have weight 0.

Now, let's sort all the edges in ascending order of their weights, and in the case of a tie - in the
lexicographical order of their identifiers.

The Kruskal algorithm gives us the minimal spanning tree. Finally, to obtain the answer to the
problem let's remove all edges that don't need to be reconstructed from MST. Don't forget to
sort the remaining identifiers in the lexicographical order!

For implementation details see Zhomart's solution.

MarriageProblemRevised
Used as: Division One - Level Two:

This problem can be easily reformulated in terms of bipartite graphs. But despite this, it shares
nothing with the matchings.

First, note that the answer is "-1" if and only if there exists a man (or woman) that dislikes all
people of the opposite gender. Therefore, we check that condition at the beginning.

Now, let's consider one special type of marriage: when a person marry himself. Such marriages
are not allowed by the problem statement, but it's easy to see that they will never appear in an
optimal solution. Therefore, allowing such strange kind of marriages won't change the answer
to the problem.

Now, let's fix some subset of men, and some subset of women. We designate each of them to
his (her) own marriage group and try to distribute all other people among those groups, if it's
possible. As we'll show below, such check can be done at O(n), which provides us an O(n2^n)
solution by bruteforcing for all the subsets (here n is the total number of men and women).

For a subset X of men (or women) we define D(X) as a subset of people of the opposite gender,
such that each member of D(X) can marry with at least one member of X. Now, if we fix some
subset X of men, and subset Y of woman we just need to check if X + D(Y) includes all men, and
Y + D(X) includes all women. Such a check can be obviously done in O(n^2), and it can be
improved to O(n) by storing preferences as a bit masks.

Also, there are two optimizations which will allow it to work much faster. Firstly, note that
there always exist a solution with [n/2] marriages - we can select either all men, or all women.
Now, if we have some current answer x, we'll consider only subsets X and Y, such that the
cardinality of X+Y is smaller then x. This will allow us to consider at most half of the subsets in
the worst case and much less on average.

Second, for fixed subset X we can calculate D(X) and consider only such subsets Y, that X+D(Y)
includes all women. Being combined, the given two optimizations will allow us to fit the time
limit with a huge gap.

SRM:357
Hotel
Used as: Division One - Level One:

This one is a classical DP problem. The state of DP is the number of customers you need to
attract. If the number of customers C is non-positive, you can get them with a cost of 0. If the
number of customers C is positive and you have already found the optimal costs for all smaller
numbers, the solution is simple: check all cities from the input and try to attract customers[i]
for the cost of cost[i]. Since you already know the cost of attracting (C - customers[i])
customers, you can find the optimal answer for C as the minimum of all (bestCost(C -
customers[i]) + cost[i]). As an implementation detail, we can shift all numbers in bestCost array
by 100, to avoid going out of bounds:

int[] bestCost = new int[minCustomers + 101];


for (int i = 1; i <= minCustomers; i++) {
bestCost[i + 100] = 100000000;
for (int j = 0; j < cost.length; j++)
bestCost[i + 100] = Math.min(bestCost[i + 100], bestCost[i + 100 - customers[j]] + cost[j]);
}
return bestCost[minCustomers + 100];

WebsiteRank
Used as: Division Two - Level Three:
Used as: Division One - Level Two:

The main part of this problem is to find for each link from site A to site B whether we should
count votes for site A towards site B or we should discard this link. To solve this question, we
build the graph of the network, which has an edge from vertex A to vertex B if and only if site A
directly links to site B. Then we build the transitive closure of this graph and start checking all
edges of the initial graph one by one. An edge A->B of the graph should be discarded if the
transitive closure of the graph has an edge from B to A. As the result we will receive an acyclic
graph.

Having that done, the problem becomes quite easy. We start calculating votes for each of the
sites, starting from the sites which do not have any incoming links. For each such site, we a) add
its number of votes to each of the sites it links to, and b) destroy all edges outgoing from it. We
are done when we compute the number of votes for all websites (or, at least, for the website
we are interested in).

I must note that the simplest implementation of transitive closure algorithm (Floyd-Warshall)
may time out on big cases. Therefore, you need to either use Dijkstra or an optimized FW
implementation. See ACRush's code for a clean (and the fastest) solution for this problem.

SRM: 358
BrokenButtons
Used as: Division Two - Level Two:
Used as: Division One - Level One:

This one was a gold mine for people who found tricky cases like optimal solution navigating to
pages over 500,000. Also, many people's solution thought it can go to page 0 even if the button
'0' is broken. You had to be very careful in reading the statement as in the actual programming
to solve it.

The Optimal entered page will never be larger than 1,000,000, so simple brute force will run in
time. Many people wrongly understood the problem statement thinking you can't enter pages
larger than 500,000. For every possible entered page (page for which the digit buttons are not
broken) we navigate first to that page and then enter the '+' or '-' buttons. The number of
presses required is the number of digits of the entered page (let's say page 100 has 0 digits) +
the absolute difference between the entered and desired page (number of '+' or '-' button
presses).

For a nice clean implementation see sluga's solution.

SameDigits
Used as: Division Two - Level Three:

Classic example of dynamic programming unfortunately proved to be too hard for division 2
coders.

Let's first solve the problem of finding out how many n-digit numbers have the required
property. Start building the number from left to right. The only things that we must know in a
certain moment is how many digits we must add, how many last digits are the same, and
whether we reach the required maximum subsequence before. Let that number be f( n,
last_same, did_reach ). It is fairly easy to get the recurrence relation from this formula, as we
know that exactly one number will increase the last_same by 1, and the other 9 numbers will
downgrade it back to 1.

To get how many numbers with exactly n digits are there we call 9*f( n-1, 1, false ). For every
number i from k to n we sum up number of solutions with exactly i digits and return the sum.
Java code follows:

public class SameDigits {


final static long MOD = 44444444;
long[][][] memo;
int K;

long f( int n, int last_same, int did_reach ){


if( memo[n][last_same][did_reach] != -1 ) return memo[n][last_same][did_reach];

if( n == 0 ){
if( did_reach == 1 || last_same == K ) {
return memo[n][last_same][did_reach] = 1;
} else {
return memo[n][last_same][did_reach] = 0;
}
}
if( k == K ) return memo[n][last_same][did_reach] = ( 9*f( n-1, 1, 1 ) )%MOD;

return memo[n][last_same][did_reach] =
( f( n-1, last_same+1, did_reach ) + 9*f( n-1, 1, did_reach ) )%MOD;
}

public int howMany( int n, int k ) {


K = k;
memo = new long[ n+1 ][ k+1 ][2];

for( int i = 0; i < memo.length; ++i )


for( int j = 0; j < memo[i].length; ++j ) Arrays.fill( memo[i][j], -1 );
long sol = 0;
for( int i = k; i <= n; ++i ){
sol = (sol + 9*f( i-1, 1, 0 )) % MOD;
}

return (int)sol;
}
}

BalanceScale
Used as: Division One - Level Two:

First, let's divide all elements from weight with greatest common divisor of weight. Now, gcd of
weight is 1. I will proove that subset of weight that can measure every element from weight is
equivalent to subset of weight for which gcd is 1. If gcd of a subset is 1, with generalization of
Bézout's identity we can easily see that we can measure all positive integers and therefore we
can measure every element from the set. If gcd of a subset is k which is greater than 1, we can
only measure integers divisible by k. GCD of weight is 1, so there exists at least one element not
divisible by k and therefore not measurable.

Now we see that the problem is equivalent to finding minimum subset of weight so that gcd of
that subset equals gcd of weight (or 1 after we divide all the elements with gcd of a set).

Factorize all the elements, so that for every element you have an array of different prime
factors of that element (we ignore multiple prime factors). The maximal number of different
prime factors for number less than or equal to 10,000,000 is 8. For every element first assume
that it's in the final answer. Then notice that for each of these different prime factors there
must be at least one element in the final answer that doesn't contain the prime factor. Do a
dynamic programming for every element trying to nullify all of his prime factors. C++ code of
the solve function follows:
(PF[i] is vector containing prime factors of i-th weight)

int solve( int k, int n, int mask ){


if( n >= w.size() ) {
if( mask == ( ( 1 << PF[k].size() ) - 1 ) ) return 0;
else return INF;
}

if( memo[k][n][mask] != -1 ) return memo[k][n][mask];

int new_mask = mask;


for( int i = 0; i < PF[k].size(); ++i ){
if( w[n] % PF[k][i] != 0 ) new_mask |= (1<<i);
}

return memo[k][n][mask] =
min( solve( k, n+1, mask ), solve( k, n+1, new_mask )+1 );
}

However, most of the coders used the fact there is not much gcd values of all subsets of a set
with 50 elements where all elements are not greater than 10,000,000. They had state DP[x] =
minimal size of a subset with gcd x. The solution is then DP[1]. See Abednego's solution. For
optimized recursion that works too, see andrewzta's solution.

SRM:359
DriveFailures
Used as: Division Two - Level Two:

Used as: Division One - Level One:

It is possible to solve this problem with dynamic programming, but the small constraints make it
unnecessary. Simply consider every possible subset of the drives, and compute the possibility
that exactly that subset is working. For example, the probability that drives 0, 1 and 3 out of 5
drives will work is (p0)(p1)(1-p2)(p3)(1-p4). Then add each probability to the appropriate
element of the output array.

UTF8Decode
Used as: Division Two - Level Three:

Wikipedia has a nice page with lots of information about UTF-8. One of the facts that can be
found is that certain bytes never appear in a valid UTF-8 file: 0xC0 and 0xC1 are illegal because
they would start a two-byte sequence for a value that should be encoded with one byte, and
0xF5 and above would encode values greater than 0x10FFFF. Any value from 0x00 to 0x7F is a
valid one-byte character, and any value from 0xC2 to 0xF4 is a valid start of a multi-byte
character, the rest of whose bytes must be in the range 0x80 to 0xBF.

Unfortunately, this is not the end of the story, as we still need to take care of

Values over 0x10FFFF. If the first byte is 0xF4, then the next byte must be at most 0x8F.
Overlong sequences, which are values encoded using more bytes than they should (e.g., values
less than 0x7FF encoded using 3 or 4 bytes). If the first byte is 0xE0, then the next byte must be
at least 0xA0, and if the first byte is 0xF0, then the next byte must be at least 0x90.
This is the exact approach taken by nu4nu, but no other competitor succeeded with it. Rather
than working out the rules, it is easier to write general code that determines whether a byte is
valid. Suppose we have some bytes that we have accepted but not yet formed into a complete
character, and we are examining a candidate byte. We can provisionally add this byte to the
sequence, then check whether it is a prefix of a valid sequence. bozzball's elegant solution
checks for the smallest and largest values that could be built from the partial character we
have, and checks whether that range overlaps the valid range for the sequence length. Ikki's
solution generates the encodings of all 1114112 characters in advance, then uses that to check
whether a partial character is a prefix of any full character. He managed to make it fast enough
using a linear search, but a feature of UTF-8 is that the byte sequences are in lexicographical
order, making it possible to binary search the list.

CropCircles
Used as: Division One - Level Two:

There are two ways in which the number of circles may be lower than expected: three points
may lie on a straight line (and hence fail to form a circle), or four or more points may lie on the
same circle. Armed with the cross product, it is a simple matter to identify straight lines. Let's
see how to count the number of unique circles from those that remain. Let each circle be
defined by the first (smallest index) three points that lie on it, in order. In order to check if an
ordered triplet is in fact a defining triplet, it suffices to check whether these three points are
concyclic with any point before the last of the three. So once we have a method for checking
whether four points are concyclic, we can proceed.

The circumcentre of a triangle can be found by taking the intersection of two perpendicular
bisectors. So a straightforward approach is to use this to find the center of three of the four
points, then of a different subset of three, and check if they coincide. The constraints are low
enough that no fancy integer arithmetic is required.

A more compact solution found by several competitors (see liympanda's solution for a clean
implementation that works in integer arithmetic) is based on Ptolemy's theorem: ABCD is a
cyclic quadrilateral if and only if AB.CD + AD.BC = AC.BD.

SRM:360
SumOfSelectedCells
Used as: Division Two - Level Two:
Used as: Division One - Level One:

In this problem, a square table turns out to be a special case. Let's investigate the non-square
case first. Suppose the width of the table is greater that its height.

The number of cells selected by Jessie will be the height of the table. Hence it is possible to
unselect one cell and select another one in the same row. In order for the hypothesis to be
correct, the integers written in these two cells must be equal. Consequently, the entire table
should look like

A1 A1 A1 ... A1 A1
A2 A2 A2 ... A2 A2
.
.
AH AH AH ... AH AH
This condition is necessary and turns out to be sufficient, because in such table, Jessie's sum will
always equal A1 + A2 + ... + AH.

Similarly, if the height is greater than the width, checking the hypothesis reduces to checking
that the table is of the following form:

A1 A2 ... AW
A1 A2 ... AW
A1 A2 ... AW
.
.
A1 A2 ... AW
A1 A2 ... AW
Now, consider a square table. Take four cells on the intersections of two rows and two
columns: Aip, Ajp, Aiq, Ajq.

Assume the following inequality: Aip + Ajq ? Ajp + Aiq. In this case, in some Jessie's selection,
she can unselect the left two integers and select the right two, thus changing the overall sum.

Hence, in order to satisfy the hypothesis, all such pairs of sums should be equal. Fortunately,
the opposite also holds: if all equalities are satisfied, the hypothesis is correct.

More detailed analysis shows that it is enough to check the following equality for all i and j:

A11 + Aij = Ai1 + A1j

By the way, that means that one column and one row determine the rest of the table.

Egor showed the best understanding of this problem, writing a coherent and fast solution first,
and making 5 successful challenges later.

TakeSubstringGame
Used as: Division Two - Level Three:
The contestants were asked to find a winning strategy for yet another impartial game. As
explained in a previously written tutorial, such games should most usually be analyzed in terms
of winning and losing positions.

In this game, position is the number written on the board. According to the rules, single-digit
numbers 1 through 9 are losing positions, because the player that faces such number can't
make a move. For all greater numbers, the following general rule should be used:

If there is a move from the current position to a losing position, then the current position is
winning.
Otherwise, it is losing.

The following pseudocode performs the analysis of all the positions.

for i = 10 to n do
for m : all proper substrings of i do
if (m > 0) and (not winning[i - m]) then
// There is a move to a losing position.
winning[i] = true;
Now, if winning[n] is true, find the smallest substracted m that leads us to a losing position and
return this m.

PrinceOfPersia
Used as: Division One - Level Two:

Based on a classical video game plot, this problem allowed two approaches.

Approach 1: MaxFlow
Note: to understand this approach one needs a thorough understanding of flow networks. A
tutorial is available in the Educational Content section.

Build a flow network according to the following rules:

For each empty cell x create two vertices Ax and Bx, and an edge Ax ? Bx with capacity 1.
For each pair of adjacent empty cells x and y create edges Bx ? Ay and By ? Ax of infinite
capacity.
If p is the Prince's cell and q is the Princess's cell, call Bp the source and Aq the sink of the
network.
Now a route from the Prince to the Princess corresponds to a simple flow of size 1 in this
network. And the suggested problem is to find the size of the minimum cut, which is the same
as the size of maximum flow, according to the Max-flow min-cut theorem.
There is a (still increasing) number of maximum flow algorithms, many of which could have
been implemented in this problem, say Ford-Fulcerson algorithm implemented by Petr in his
solution.

Note that an infinite maximum flow corresponds to the answer -1.

Approach 2: Specificity of the problem


The answer is -1 if and only if the two 'P' cells are adjacent.

If they are not, here's a non-optimal solution for Jaffar: lock the poor Princess. She has 0 to 4
empty cells adjacent to her cell, so put obstacles in each of these cells and prevent her from any
movement.

Hence, the correct answer for the problem is no more than 4.

How can we check that the answer is 3 or less? Iterate over all triples of empty cells, and for
each triple try to put obstacles in these three cells and check whether the Prince and the
Princess are disconnected. To check this property use any graph search algorithm, DFS being
probably the easiest to implement.

Similarly, (better even before checking triples) check the empty set of cells, all single empty
cells and all pairs of empty cells. As soon as the set being checked separates the heroes, return
the size of that set.

If S is the size of the maze (height × width), the number of sets to check is O(S3) and each check
takes O(S), thus the complexity is O(S4).

You might also like