CodeChef is a non-commercial competitive programming community
Login
Username (New User? Signup) Password (Forgot Password?)
Signup
Login or
Signup with
Connect
Note
  • Publicize your achievements on your Facebook Wall.
  • Challenge your friends or ask them for help.

Site Navigation

  • PRACTICE
    • Easy
    • Medium
    • Hard
    • Challenge
    • Peer
  • COMPETE
    • All Contests
    • June Long 2012
    • May Cook-Off
    • May Long 2012
  • DISCUSS
    • Forums
    • Blog
    • Wiki
    • Facebook
    • Twitter
  • COMMUNITY
    • CodeChef Meetups
    • Campus Chapters
    • Host your Contest
    • User Groups
    • CodeChef TechTalks
    • All Educational Initiatives
  • HELP
    • Frequently Asked Questions
    • FAQ for problem setters
    • Problem Setting
    • Tutorials
    • Long Contest Ranks
    • Short Contest Ranks
    • Event Calendar
  • ABOUT
    • About CodeChef
    • Team CodeChef
    • Press Room
    • CodeChef Financials
    • CodeChef Sponsorships
    • CEO's Corner
    • Contact Us
    • About Directi
Home » Wiki » December CookOff Contest Problem Editorials

December CookOff Contest Problem Editorials

 

COMMUTE (written by Zac Friggstad)

Nothing really special here. Let t_i be the earliest time we can arrive at station i with the base case t_0 = 0. Then given t_i we can easily compute t_{i+1} by waiting from time t_i until the next train departs from station i, and then adding the travel time to this departure time to get t_{i+1}.

 

You can view the solutions here:

Problem Setter Solution

Problem Tester Solution

 

 

PAIRING (written by Zac Friggstad)

A greedy strategy works here. Consider the pairs in the reverse of the order they appear. When considering a given pair, we greedily take it if neither of the chefs were in a used pair earlier. To see why this is optimum, suppose an optimum solution had a higher total value than our greedy solution. Let i be the greatest index where our solution disagrees with the optimum. Based on our greedy selection strategy, it must be that we took the i'th pair whereas the optimum doesn't include the i'th pair. But then we can improve the cost of the optimum solution by deleting all pairs j with j < i and adding pair i. This is an improvement because of the exponentially increasing values of the pairs: 2^1 + 2^2 + ... + 2^{i-1} is strictly smaller than 2^i. This contradicts optimality of the considered solution.

 

You can view the solutions here:

Problem Setter Solution

Problem Tester Solution

 

PREPARE (written by Zac Friggstad)

Perhaps the simplest approach is to use binary search problem coupled with a dynamic programming subroutine. Given a value T, we can determine if it is possible to prepare all dishes in time T. All dishes that can be prepared by the other cooks in time at most T will be delegated to them. For the remaining dishes, we run a subset-sum style algorithm to determine if the Chef and his assistant can prepare them in time T. This can be done by building a table d[] where d[k] is true if and only if there is some subset of dishes of total preparation time k. We only have to build this table up to time T. Let the total preparation time (by the Chef and his assitant) of the remaining dishes be S. Then the remaining dishes can be prepared in time T if and only if some k with k <= T and S-k <= T has d[k] being true. That is, the Chef can prepare some dishes in time k and his assistant can prepare the remaining in time S-k.

There is a direct dynamic programming approach that avoids binary search which avoids the O(log n) overhead of the binary search method (as long as some sorting is done before hand), but it's simplest to describe this approach and it was fast enough for the problem.

 

You can view the solutions here:

Problem Setter Solution

Problem Tester Solution

 

PUZZLES (written by Zac Friggstad)

This is the standard 3SAT problem where each clause depends on precisely three different variables and each variable appears in at most 3 clauses. Such instances can be solved efficiently. Form a bipartite graph with a node for each clause on one side and a node for each variable on the other. For each clause C, add an edge from the node for C to each of the three nodes corresponding to variables that appear in C. I claim there is a matching in this graph that involves each clause node. Before arguing this, we see that we can then satisfy the instance by assigning, to each matched variable, the value that will satisfy the clause it is matched to. Variables that are unmatched can be assigned anything.

Recall that Hall's matching theorem states that a bipartite graph with bipartitions X and Y has a matching involving every node in X if and only if each subset X' of X has at least |X'| neighbors in Y. This is true in our case. Consider a subset C' of clauses. The number of edges with one endpoint in C' is precisely 3|C'|. On the other hand, let V' be the subset of variables that are adjacent to some clause node in C'. Since each variable appears in at most 3 clauses, then the number of edges with one endpoint in V' is at most 3|V'|. We counted the same set of edges in two different ways which shows |C'| <= |V'|, so by Hall's theorem there is a matching involving every clause node.

Rajiv, this months tester, has a nice alternative linear-time solution. It solves the slightly more general problem when each group can contain a repeated number, but the total times a number appears is still at most three (e.g. it can appear in at most two groups if it is used twice in some group). It does not generalize as neatly to instances where each group has at least K distinct numbers and each number appears in at most K groups when K is some given number whereas the matching approach does. I'll sketch the details. Consider a number Z:

i) If Z appears with the same sign in all groups, then assign it the value that will satisfy all of these groups

ii) If Z appears in two different groups with opposite sign, then place it on a "dependency stack" which will be implicitly described in the following. Remove these two groups and form a new group that is the union of the original groups (without Z). This new group will contain at least three numbers. Now, if the resulting instance is solved then using the same assignment will satisfy at least one of the two original groups. Now, fix Z to have the value that will satisfy the other group.

iv) A similar, but messier, rule is used if Z appears in three groups with both Z and -Z appearing in at least one of these groups. I'll leave the details as an exercise.

A careful implementation of these ideas leads to a linear-time solution.

 

You can view the solutions here:

Problem Setter Solution

Problem Tester Solution

 

SEEDS (written by Zac Friggstad)

Let x_0, x_1, ..., x_{d-1} be the seed values we are trying to discover. It is easy to see by induction that every value x_i is a linear combination of these seeds. Furthermore, we can use the usual fast matrix multiplication trick to discover the coefficients in this linear combination (I'll explain this below if you haven't seen it). So, for each of the x_i given in the input we have a linear equation with unknowns being the seed values. Once we determine all of these equations, it is a simple matter of solving this linear system with Gaussian elimination to determine if there are none, one, or many solutions for the seed values.

The matrix multiplication trick I'm alluding to is the following. For i >= 0, let z_i denote the column vector (x_{i+d-1}, x_{i+d-2}, ..., x_{i+1}, x_i)^T. The main idea is that there is a matrix A such that A z_i = z_{i+1} for every i >= 0. The first row of A consists of the a_{d-1}, ..., a_0 values given in the input and of the remaining rows, the j'th such row has all zeros except for a single 1 in column j-1 (try this on a few simple recurrences like the Fibonacci series). Then multiplying z_i by A "shifts" the entries down and the top entry becomes x_{i+d} by the recurrence. By induction on k >= 0, we have that A^k z_0 = z_k where z_0 is the column vector of the seed values we are trying to discover. The neat thing is that we can compute A^k in O(log k) matrix multiplications by using fast exponentiation. Just remember to keep all intermediate results reduced modulo 2. The coefficients of the linear combination of the seeds that yield x_i are then found on the bottom row of the matrix A^i.

This easily generalizes to the case when we are trying to discover the seeds when the recurrence is taken modulo p for some arbitrary prime p. However, it would involve implementing modular inversion and I thought there was enough to do for this problem in short contest already :)

 

You can view the solutions here:

Problem Setter Solution

Problem Tester Solution

 


Comments

  • Login or Register to post a comment.

In SEEDS one can obtain algo

anton_lunyov @ 20 Dec 2010 01:25 AM

In SEEDS one can obtain algo with complexity O(H*d*d+H*k*d+d*d) per test, where H=31

First note that matrix multiplication by modulo 2 can be done in O(d*d) time (since d<32) using bit arithmetic:

(A*B)(i,j) = BitCount(rowA[i] & colB[j])

BitCount(x)=BitCount(x/1024)+BitCount(x%1024)

and numbers BitCount(x) for 0<=x<1024 simply precalculated.

The main trick consider transpose of A.

Denote it again by A.

Then the coefficients of the linear combination of the seeds that yield x_i are then found on the last column of the matrix A^i. But last column of matrix is the product of matrix and the column u = (0,0,...,1).

So here the algo.

Precalc all binary powers A[h] = A^(2^h) for 0<=h<H --> O(H*d*d)

For each of 0<=j<k we need find A^i(j) * u

Let i(j)=2^(r_0)+2^(r_1)+...+2^(r_q) then

A^i(j) * u = A[r_0]*(A[r_1]*...*(A[r_q]*u))

But product of matrix and vector can be calculated in O(d) time using binary arithmetic tricks above. Since q<=H we see that this step done in O(k*H*d) time.

And finally we need apply Gaussian algo which is usually O(d*d*d) but again with binary arithmetic tricks it becomes O(d*d).

My algo in the contest is d time slower since I did not implement these binary tricks.

But this is because I first solve the problem with p=1000000007 where there is no such tricks.

And even without this tricks its in more than ten times faster then other solutions.



I loose first place because of printing “no solutions” instead of “no solution”.

What a pitty! :-(

In the question "Preparing

jimmy valentine @ 20 Dec 2010 02:33 AM

In the question "Preparing Dishes" , I could not figure out why we are using binary search algorithm here. Please help.

Thanks.

CodeChef is a non-commercial competitive programming community
  • About CodeChef
  • About Directi
  • CEO's Corner
  • C-Programming
  • Programming Languages
  • Contact Us
© 2009 Directi Group. All Rights Reserved. CodeChef uses SPOJ © by Sphere Research Labs
In order to report copyright violations of any kind, send in an email to copyright@codechef.com
CodeChef a product of Directi
The time now is:
CodeChef - A Platform for Aspiring Programmers

CodeChef was created as a platform to help programmers make it big in the world of algorithms, computer programming and programming contests. At CodeChef we work hard to revive the geek in you by hosting a programming contest at the start of the month and another smaller programming challenge in the middle of the month. We also aim to have training sessions and discussions related to algorithms, binary search, technicalities like array size and the likes. Apart from providing a platform for programming competitions, CodeChef also has various algorithm tutorials and forum discussions to help those who are new to the world of computer programming.

Practice Section - A Place to hone your 'Computer Programming Skills'

Try your hand at one of our many practice problems and submit your solution in a language of your choice. Our programming contest judge accepts solutions in over 35+ programming languages. Preparing for coding contests were never this much fun! Receive points, and move up through the CodeChef ranks. Use our practice section to better prepare yourself for the multiple programming challenges that take place through-out the month on CodeChef.

Compete - Monthly Programming Contests and Cook-offs

Here is where you can show off your computer programming skills. Take part in our 10 day long monthly coding contest and the shorter format Cook-off coding contest. Put yourself up for recognition and win great prizes. Our programming contests have prizes worth up to Rs.20,000 and $700lots more CodeChef goodies up for grabs.

Discuss

Are you new to computer programming? Do you need help with algorithms? Then be a part of CodeChef's Forums and interact with all our programmers - they love helping out other programmers and sharing their ideas. Have discussions around binary search, array size, branch-and-bound, Dijkstra's algorithm, Encryption algorithm and more by visiting the CodeChef Forums and Wiki section.

CodeChef Community

As part of our Educational initiative, we give institutes the opportunity to associate with CodeChef in the form of Campus Chapters. Hosting online programming competitions is not the only feature on CodeChef. You can also host a coding contest for your institute on CodeChef, organize an algorithm event and be a guest author on our blog.

Go For Gold

The Go for Gold Initiative was launched about a year after CodeChef was incepted, to help prepare Indian students for the ACM ICPC World Finals competition. In the run up to the ACM ICPC competition, the Go for Gold initiative uses CodeChef as a platform to train students for the ACM ICPC competition via multiple warm up contests. As an added incentive the Go for Gold initiative is also offering over Rs.8 lacs to the Indian team that beats the 29th position at the ACM ICPC world finals. Find out more about the Go for Gold and the ACM ICPC competition here.

Domain Name Registration, Web hosting, and Website Design provided by BigRock.com