TopCoder Tips

28
TopCoder Training Camp >> Tutorials This part contains some tutorials on different aspects that I hope can help us at getting better problem solvers and programmers. It begins easy with simple programming tips mainly intended for beginners and goes on to topics like game theory, algorithm techniques and discussion of algorithms that have proven to be useful every now and then. Each tutorial also provides references to TopCoder problems where the material was or could've been used, so you can directly try to apply what you've just learned. Note: I'm not really active at TC anymore (only rarely participate). Read "under construction" as "I started to think/write about this but I never finished something worth publishing and right now it's rather unlikely I ever will". For Starters o TopCoder for Dummies - Things that are good to know when you're new to TopCoder, somehow a basic survival kit. o Basic (programming) tips . If you're a beginner at programming, these tips might save you quite a lot of time during the contest and make your code less errorprone. o TopCoder Survival Kit - Some advice I made up a while ago and mainly for myself because I was so angry that I made the same stupid mistakes over and over again. General Algorithm Techniques o Dynamic Programming (under construction) - A technique useful for a lot of TopCoder problems. o Brute Force (under construction) - A technique even more useful. Algorithms

Transcript of TopCoder Tips

Page 1: TopCoder Tips

TopCoder Training Camp >> Tutorials

This part contains some tutorials on different aspects that I hope can help us at getting better problem solvers and programmers. It begins easy with simple programming tips mainly intended for beginners and goes on to topics like game theory, algorithm techniques and discussion of algorithms that have proven to be useful every now and then. Each tutorial also provides references to TopCoder problems where the material was or could've been used, so you can directly try to apply what you've just learned.

Note: I'm not really active at TC anymore (only rarely participate). Read "under construction" as "I started to think/write about this but I never finished something worth publishing and right now it's rather unlikely I ever will".

For Starterso TopCoder for Dummies  - Things that are good to know when you're

new to TopCoder, somehow a basic survival kit.o Basic (programming) tips . If you're a beginner at programming, these

tips might save you quite a lot of time during the contest and make your code less errorprone.

o TopCoder Survival Kit  - Some advice I made up a while ago and mainly for myself because I was so angry that I made the same stupid mistakes over and over again.

General Algorithm Techniqueso Dynamic Programming  (under construction) - A technique useful for

a lot of TopCoder problems.o Brute Force  (under construction) - A technique even more useful.

Algorithmso Connected Components and FloodFill  - Identify the connected

components of a graph. Special case: identify the regions of same color in a matrix.

o Permutations  (under construction) - What are they, how do I generate all, what are the limits concerning runtime, how do I find the best permutation, how do I recognize that my problem has to do with permutations, ...

o Sets, Subsets, ...  - What are they, how do I generate all, what are the limits concerning runtime, how do I find the best subset, how do I recognize that my problem has to do with subsets, ...

Specific Topicso Catalan Numbers  - A little introduction to Catalan Numbers,

motivated by the "Uniscraper" problem of SRM 115.o Game Theory  (under construction) - Explains the Nim variants that

recently appeared in TopCoder contests.

Page 2: TopCoder Tips

Stefan Pochmann

Last modified: Fri Oct 4 02:18:40 MET DST 2002 

TopCoder Training Camp >> Tutorials >> TopCoder for Dummies

Last modified: Thu Jan 30 22:22:48 MET 2003

Jan 30, 2003: I rewrote large parts of this page and included some screen shots.

Recently I've spent quite a while in practice room 1, answering questions of newbies, looking at hundreds of programs and challenging some of them. From that experience, I thought it might be a good idea to address some issues I came across there. First some more important things.

General note: TopCoder sometimes changes its website/system a bit and I might not be able to keep this page up to date, although I'll try to. You can help me - when you notice a mistake here or would like me to include or rewrite something, please let me know.

Ok, let's begin...

TC = TopCoder (a commonly used abbreviation)

SRM = Single Round Match (another abbreviation you should remember). This is just one match, not one of the tournaments TopCoder offers every once in a while. There's usually one SRM each week. Look at the schedule for more info.

Arena = The TopCoder Arena applet. This is the main TopCoder system (other than their website). It's a Java applet that allows you to chat with others, register for contests, participate in contests, practice in practice rooms, etc... I'll show you some screenshots soon.

Before you can use the Arena applet, you have to become a TopCoder member. It's free, you don't have to buy anything, you don't get spammed, it's all good ;-) There are also some parts of the TopCoder website that you can't access unless you're a member. This includes the "Algorithm Discussion" round table and solution programs of other members, so you're really missing the coolest parts if you don't join the party.

Page 3: TopCoder Tips

There are several ways to start the arena and each has it's own advantages and disadvantages. You should try several of them to find out what's the most convenient way for you.

o With a webbrowser. Click on the "Competition Applet" button on the TopCoder website.

o With an appletviewer. Start it like this:appletviewer "http://www.topcoder.com/?t=arena&c=arena"

o With Java Web Start. I haven't tried this yet, but you can find out more about this on the bottom of the TC website start page under "Java Web Start".

o With your own applet viewer application. I do not recommend this, although this is the way I do it ;-)

In all cases, a little window will pop up with a "Load Competition Arena" button. Click on it and then enter your TopCoder login and password in the next window:

I addition to registering as a TC member you also have to register for each SRM you want to participate in. Registration begins 3 hours before the start of the contest and ends 5 minutes before the start. Look at the schedule to get to know about times of future contests. You might be in a different timezone than TopCoder, so find out the TC time by clicking on "[Get Time]" in the upper left corner on their website. Alternatively you can click through "Active Contests" -> "(The Contest)" -> "Schedule" to get a detailed schedule already translated to your timezone (hopefully correctly ;-).

You register for a match inside the arena applet. Click through "Active Contests" -> "(The Contest)" -> "Register" and then follow the instructions.

Shortly before the contest (usually about three minutes, you'll get a popup-window with a message that tells you) you can enter your contest room by clicking through "Active Contests" -> "(The Contest)" -> "Enter".

I strongly recommend that you just go ahead and play around with the Arena applet and the TopCoder website. Click on everything you can to find out what it can do for you. There are lots of treasures out there and I won't explain all of them here. This is how the Arena looks like when you enter it:

TopCoder matches have four phases:

Page 4: TopCoder Tips

1. Coding phase (75 minutes) - People read the problems, write solution programs and submit them. The programs are not evaluated in this phase, so the points you get are not final, you might lose them in phase 3 or 4. The Arena will look similar to this in the coding phase:

2. Intermission (5 minutes) - A short break to calm down, refresh yourself, chat with others, prepare challenges for phase 3, ...

3. Challenge Phase (15 minutes) - You can look at other people's programs and challenge them. If the program fails on your challenge input, your challenge is "successful", you gain 50 points and the poor guy/girl loses all points for that problem. Otherwise you lose 50 points. Each program can be successfully challenged only once. So don't look for bugs in programs that were already successfully challenged by somebody else unless you search for new challenge ideas. Note that you can't challenge if you don't have more than zero points and you can't challenge a program twice, so you might want to be careful. But don't be too careful, otherwise somebody else will be faster ;-) How do you challenge? Click on the bright "Summary" button. The following window will pop up:

Here you can see some information about who did what. Right-click or double-click on the points somebody got for his/her solution. This will pop up another window showing you the program and with a "Challenge" Button". If you find a bug, click that button. Then you have to enter an input on which you think the program will fail. This input has to be valid as defined in the problem description. You can *not* challenge somebody with invalid input.

Note that in the practice rooms (choose one with through the Arena menu) all this works exactly the same way as in real matches, but of course there are no time frames, so you can submit/challenge/... whenever you want to. During a real contest, you can't challenge or even look at solutions of others before the challenge phase.

4. System Testing Phase (? minutes) - Here you just relax and wait for TopCoder to test all submitted programs with their own inputs they prepared in advance plus the inputs from successful challenges by us in phase 3. If TopCoder has no problems, it should take somewhere

Page 5: TopCoder Tips

between 10 and 30 minutes. Sometimes they have to fix things first, so it can also take much longer...Many people wait in the lobby chat room ("Lobbies" in the menu) and there's always a lot of discussion going on there, including the current status of the system tests. One advice: When you just entered the lobby and want to ask the admins something, wait 20-30 seconds. Usually if there's an issue with the system test or something like that, dozens of people ask the same questions again and again and the admins have to give the same answers again and again. Their time is spent more wisely fixing the issues.

The input is always guaranteed to be valid. You don't have to write extra code to check if it is valid. Each problem exactly states what a valid input is. Read that part carefully.

How many points you get for a problem depends solely on the time it took you from first opening the problem description until you submit a solution for it. There is no penalty for compiling and testing. Note that if you open a problem, close it again, solve another problem, and then return to the first one, that the clock for the first one was ticking all the time. Also, the points do *not* depend of the elegance or speed of your solution. Well, you'll lose all points if you're too slow (need more than 8 seconds), so that was not exactly true.

Since SRM 88 we have the possibility of multiple submissions. That is, you can replace your solution with another one as often as you want to. However, you will be punished by losing 10% of the maximum points every time and furthermore of course the clock kept ticking.

In practice rooms you can run the system tests that were use in the original contest by going through the menu item "Practice Options". You should always do this when you've finished a program to make sure it is correct. And it's so easy to use, just two clicks away. Note that it can take some time (about 10-60 seconds) until the popup-window with the results appears, so just be patient.

You can also clear your problems and then resubmit them. If you have a problem window opened, close it first, otherwise it won't be cleared properly. And don't forget to have your code locally on your own machine in a file or editor (not in the applet), because it will be deleted on the TopCoder server ;-) Well, since multiple submissions are allowed now, this feature is much less important than it was before.

In Java and C# you have to make both the class and the method public. In C++, only the function needs to be public. As a demonstration of what a solution looks like, I'll show you solutions for the easy problem in practice room 1. Note that these solutions do the wrong thing, because I don't want to steal the fun of solving the problem from you. But they still show you the

Page 6: TopCoder Tips

general structure you have to write. All that's left to do is to change the function body so that the program computes the correct thing...

Java

public class Pencil { public int bestPencil ( int[] deviations ) { int sum = 0; for( int i=0; i<deviations.length; i++ ) sum += deviations[i]; return sum; }}

C++

#include <vector>#include <algorithm>using namespace std;

struct Pencil { int bestPencil ( vector<int> deviations ) { int sum = 0; for( int i=0; i<(int)deviations.size(); i++ ) sum += deviations[i]; return sum; }};

C#

public class Pencil { public int bestPencil ( int[] deviations ) { int sum = 0; for( int i=0; i<deviations.Length; i++ ) sum += deviations[i]; return sum; }}

Now some more things that came to my troubled mind but that are not so important. They are also more like advice from myself and other people might have different opinions about some of this. Feel free to hate me if you disagree with something. Or better, tell me about it and I might change my mind.

Practice in practice rooms. Solve problems and challenge others there. If you can't find a bug in programs of others, look at already successfull

Page 7: TopCoder Tips

challenged programs. They do contain bugs and you can still try to find them and improve your challenging skills.

Quite a few people tend to use their own IDE locally on their own computer. Writing, compiling and testing the programs might be easier for you in your own environment than in the TC arena applet. You can the just copy your code to the applet when you're done. Some of the Arena plugins you can get from the TC website might be helpful to support you.

Use the round tables on the TC website. People discuss problems and solutions and all other stuff there.

Use the chat correctly, especially in the lobby chat room. There are so many people writing at the same time that one can easily miss something if you don't address it to her/him so that it gets highlighted for her/him. You can do that by clicking on "<<" on the left of where you enter the message and then choose "reply to" or "whisper" and the name of the person. Alternatively you can also enter something like "/mesg TheSlayer blah blah..." in the chat text field, which is the same as "whispering" to that TheSlayer guy...

Stefan Pochmann

TopCoder Training Camp >> Tutorials >> Basic (programming) tips

As I've spent quite a while in practice room 1 recently, looking at hundreds of programs (and challenging some of them), I've seen a lot code that is needlessly complicated. On this page, I'll give some advice how to get your programs shorter, faster and less errorprone. Basically most of the advice is to use the library that comes with each programming language. Note that I can't code C#, so my examples will be in C++/Java only, but since C# has an amazing similarity to Java...

 

An Example

I'll discuss some issues by taking the easy problem "Pencil" in practice room 1 as an example. The input to the problem is an array of up to 50 integers in the range -1000 to 1000 (inclusive). The goal is to find the minimum distance to zero of any of the input numbers. Examples: input { 3, -5, 2 } has result 2 and input { 4, -3, 11 } has result 3.

Page 8: TopCoder Tips

Many times I have seen programs similar to this one:

1: int bestPencil ( int[] deviations ) { 2: if( deviations.length == 0 ) 3: return 0; 4: int best = 1001; 5: for( int i=0; i<deviations.length; ++i ){ 6: int temp = deviations[ i ]; 7: if( temp == 0 ) 8: return 0; 9: if( temp < 0 )10: temp = temp * -1;11: if( temp < best )12: best = temp;13: }14: return best;15: }

This program is correct, but of course I've also seen a lot of bugs in programs (but this should be covered by another tutorial, let me just say that many people incorrectly compute -5 for the input { -5 }. Look at some successfully challenged submissions in the practice room). Now what would I change in the above program?

1. First of all, the special case that the array is empty doesn't need to be handled (lines 2-3). Why? Because an empty array is not a valid input and the input is guaranteed to be valid. Also, it's of course not defined that in this case the answer thould be zero, don't know where people got this idea from. Some return -1 or even throw an Exception. Just remove lines 2-3.

2. The special case that a zero occurs in the input doesn't need to be handled by extra code (lines 7-8). The program would be correct without it. Of course it would check the remaining numbers, too, which might be slower. But there are only 50 numbers anyway, no need for any optimization! Furthermore, if there are no zeros, then this actually slows the program down a bit.

3. I'd write temp = -temp; or temp *= -1; in line 10.4. Even easier, the distance of a number from zero is called the absolute

value of that number and there are library functions you can use. The lines 9-10 can simply be replaced bytemp = abs( temp ); (C++) or temp = Math.abs( temp ); (Java).

5. You can use the min-function of the library to replace lines 11-12 by best = Math.min( best, temp ); (Java) or best = min( best, temp ); (C++). Note that this you only have to type the possible new minimum value only once this way. Btw, micro$oft was too stupid too include min and max at least for VC++, so you might have to do it on your own if you work with that crap. On the TopCoder server, they do exist, don't worry.

6. You don't need to use a temporary variable, especialy if you use the library functions I mentioned (if you don't use them, a temporary variable is indeed good, otherwise you might have to repeat lots of long code.

Page 9: TopCoder Tips

If you apply the tips, the program now looks like this:

1: int bestPencil ( int[] deviations ) { 2: int best = 1001; 3: for( int i=0; i<deviations.length; ++i ) 4: best = Math.min( best, Math.abs( deviations[ i ] )); 5: return best; 6: }

If you're new to programming, this might be a bit confusing because several things happen in just one line. Don't worry, you'll get used to it fast if you try to. The main things you should believe by know:

Writing long code takes more time and gives you more opportunities to make mistakes.

Doing unnecessary things makes your program longer. Knowing and using library functions can do miracles for you. It's fast to use

them and they probably don't have bugs.

 

Sorting

Another solution for the problem is to first turn every value in the array into its absolute value, then to sort the array and simply take the first element:

1: int bestPencil ( int[] deviations ) { 2: for( int i=0; i<deviations.length; ++i ) 3: deviations[ i ] = Math.abs( deviations[ i ] ); 4: Arrays.sort( deviations ); 5: return deviations[ 0 ]; 6: }

As a general advice, sorting can make many things easier and it's not that expensive. The library functions run in time O(n log n), so 50 is just a joke. Want to find the minimum (maximum) value? Sort and pick the first (last) element. Want to find the element that has equally many smaller and larger elements in the array (also called the median)? Sort and pick the middle element. Want to find the two numbers with the smallest difference but it takes too long to test all n(n-1)/2 pairs? Sort and only test the n-1 pairs of adjacent numbers in the array.

For finding the minimum or maximum, sorting is an overkill and a simple loop would be enough. However, it's usually faster and less errorprone to just call a library function and then just pick the right element. And sometimes you'll want to have the array sorted anyway and minimum/maximum is just one more reason to have it sorted. For the median, linear time algorithms exists, but are much more

Page 10: TopCoder Tips

complicated to code. Almost never worth the pain. For the minimum-difference-pair, I believe the sorting method is optimal.

In general, it often helps to think "What if the array would be sorted? Would that make my life easier?". And don't forget: the library already provides fast, correct and easy-to-use sorting functionality, there's absolutely no reason to write your own sorting code. You'll only lose time and make mistakes.

 

Library References

Now how do you get to know the library that comes with your language? Here are some references I know. If you know another one (especially for C#), please tell me.

Sun: Java API - Note that this link goes to Java 1.4 and TopCoder so far uses Java 1.3, so if you see a "Since: 1.4" somewhere (for example in java.lang.String.replaceAll(...)) then you can't use it yet. TopCoder is currently evaluating if they can switch to Java 1.4.

Nicolai Josuttis: The C++ Standard Library : A Tutorial and Reference - This book is very very good. And the author sits in the standardization committee. Do I have to say more?

Rogue Wave: Standard C++ Library Class Reference - Even though it's from a company, this information is - as far as I know - conform with the official C++ standard library.

SGI: C++ Standard Template Library Programmer's Guide - Same here, also seems to fulfill the standard. What's more: they have added some stuff like hash_set, and they are also supported on the TopCoder server.

C++ Reference  The iostream part is quite nice, but the STL part is missing so far.

 

The most useful library parts

Ok, now that you know where you can get the information, I'll give you some advice on what to look at. Learn how to use this stuff, it's so worth it, I promise.

Java - Look what the classes java.lang.Math and java.lang.String can do for you. Also, you'll find converters between data types in other classes of the package java.lang, for example Integer.parseInt(...) which takes a String and returns an int. Very useful are some classes in the package java.util, in particular the following four, which you can see used very often in my Division 2 solutions. One downside Java has is that TreeSet, TreeMap, etc

Page 11: TopCoder Tips

all work on Objects, so if you want to use basic values like int or boolean, then you have to convert them to Objects in one way or the other (for example String s = "" + i; or Integer iObj = new Integer( i );

o StringTokenizer - Powerful to split Strings into parts, makes life a lot easier sometimes.

o Arrays - For sorting, searching, and some other stuff.o TreeSet - To collect a bunch of items without having duplicates, for

fast lookup whether you've already seen an item, for having the items in sorted order at the end, etc.

o TreeMap - To be able to collect some data for some items. Example: to store the weight of some people where the people are referenced by their names as Strings. This is similar to an array, but your indices are not limited to non-negative integers. They can be strings, sets, anything. Plus, if you do use integers as indices but they can range from, say, 1 to 1,000,000,000 then you can't have an array that big. But if you know you will only use a few of them, then a TreeMap will work fine.

C++ - I won't repeat what they're good for, you can read that in the Java part above, but here are the names in C++: The class template set<...> is similar to TreeSet, map<...> is similar to TreeMap and when you include <algorithms> you have access to sweet things like sort(...), binary_search(...), min_element(...) etc. Just browse the resources I gave you earlier to find more treasures. To convert between strings and numbers, I usually use istringstream or ostringstream objects, but the good old char[]/sscanf(...)/sprintf(...) combination is still useful sometimes.

C# - ???

 

Extreme cases

Make sure that you get all extreme cases right. For example, I've seen many solutions to the Pencil problem that could handle it if the input contained some negative numbers among some positive ones. But many failed when given a single negative number as input. People tend to think too big. Very often it's the smallest cases where people fail. In the same practice room, a lot of solutions for the medium problem fail if N=1 or N=2. So my advice: check if it works for a single number or for N=1 or for an empty string or array or for N=0, whatever is the smallest valid input. If negative numbers are allowed, try a single negative number. Try zero alone.

Also check the largest valid inputs. If you're not careful enough, your algorithm might be way to slow. Or equivalently bad, you might walk out of bounds of an array. For example, I've seen a solution for the medium problem in practice room 1 with an int[10000] and then the person filled the array from indices 0 to N. But N

Page 12: TopCoder Tips

could be 10000, and it was Java, so he threw an exception and lost all points. General advice for this: Always make your arrays a bit longer than needed, it can't hurt, but might save you.

Don't handle extreme cases that can't occur. In the Pencil problem, quite a lot of people immediately return zero if the input array is empty. But an empty array is invalid input, this can never happen. In the medium problem, some solutions check for N=0, when it was unnecessary because that's no valid input (depending on your algorithm it might be necessary, for example if you have a recursive solution where N is decremented). Writing extra code here is wasted time and it only introduces an opportunity to ruin everything with a bug in code that shouldn't be there.

That said, I'd recommend to always look very carefully at the specification of what a valid input is, what the extreme cases are. Don't handle too few cases, but also don't handle too many.

And before I forget it: Read the match editorials, especially the "Problem Set Analysis & Opinion" and the excellent "Lessons Learned the Hard Way". They discuss how people failed and how the problems could've been solved. Very valuable.

 

Testing

Some people may disagree with this, but this is my opinion: I never submit a program before it correctly solves at least *all examples* given in the problem statement. Never. Sometimes I even add one or two test cases, mostly extreme cases. I fail a lot less often since I adopted this strategy (16 correct out of 17 submissions in my last 7 contests (SRMs 84-91), yaeh ;-). Of course there's the exception when I know that an example is wrong, but then I try to correct it.

 

Final words

My last advice: Go to the practice rooms and try to apply the tips. If you have solved a problem, try to solve it more elegantly with a shorter program*. Look how other people did it. Try to learn from the more experienced programmers. Don't be too shy to ask people for help if you don't understand something or if you don't see how on earth somebody managed to successfully challenge you.

*: No, this does not mean that I suggest to use variable names that are just one character long, actually I think this is a bad idea unless you use a variable name for a standard task (for example, I always use i and j as the coordinates of matrices).

Page 13: TopCoder Tips

Stefan PochmannLast modified: Wed Jun 5 13:45:35 PDT 2002

TopCoder Training Camp >> Tutorials >> TopCoder Survival Kit

Author: Stefan PochmannLast updated: March 23, 2002

Note: I've written this a long time ago, so maybe I have changed my mind about some things in the meantime. Moreover, some of this stuff has already made its way into my other tutorials, for example the API links. Nevertheless, I believe that it still contains some valuable advice, especially for newbies.

This page contains some more or less general rules that I came up for myself to be better in TopCoder programming contests. However, most of them should apply to other programming contests or even real life, as well.

But first a general remark about why there's no good reason to not participate in the contests: Even if you lose, because you make stupid mistakes like the ones I recently made, you still win! Do you think I would've written this survival kit without having mistakes as a reason? Do you think I would've thought so much about this stuff? Making mistakes was in the long term even better, because now I've learned more. You simply can't lose!

Note: If I'm sometimes rude here, please don't take it personally. I'm screaming at myself. This page is more like a written soliloquy for me.

 

General problem solving structure

Here are some donts:

Don't submit your program before having tested it.  Exception: You just finished coding and it's 5 seconds until the end of the contest. This is the only exception. Remember: In TopCoder you don't have a second chance to submit.

Don't program your algorithm before you have designed and tested it. I tend to fly over the problem statement, not reading everything, because I know what the want anyway. Right? Wrong! Usually I miss an important constraint and go for the wrong goal.

Page 14: TopCoder Tips

Don't design your algorithm before you have understood the problem. Several times I had not fully understood the problem. I just thought "Oh well, this is similar to the XYZ problem that I already know". And then I solved the wrong problem. Great idea, dumbass!

You have not understood the problem before you have read the whole description, and analyzed the examples. If you don't read everything, you'll miss the most important sentence. I promise!

Or in chronological order, this is what you should do:

1. Read the problem description.  Write down all important things: What is the data? What is the unknown? What are the constraints?

2. Analyze the examples.  More on examples later in the survival kit.3. Make sure you have understood the problem and know all the

constraints. What is the goal? Do the examples all make sense?4. Design your algorithm and evaluate it.  Does it work for the

examples? Is it fast enough? Note: If possible, this phase is on paper!5. Program your algorithm.  Now that's what you wanted to do all the

time, right? Now you're allowed to.6. Test your program with the given examples.  Come up with new

examples if the given ones are not enough. Remember: In TopCoder you don't have a second chance to submit!

Last rule: there's always an exception to (almost) every rule. For example, a simple test program can sometimes help you to understand the problem. In that case, you can change the fixed process above.

 

Examples

Read all examples. At the very least glance over them. But do glance over them. Note that this is not the same as skipping them. I divide examples as follows: trivial vs non-trivial, full vs magic.

Trivial examples are ... well ... trivial. They are so small and simple, that you can't learn much from them. But remember Murphy's Law: as soon as you skip the most simple example, it will later turn out to be the most important one. For example, the one that highlights a special case where n=0.

Magic examples are so big that you can't understand the answer, which of course only includes the return value. In contrast, a full example is understandable, either because it's small enough or because the steps that have lead to the solution are given.

Page 15: TopCoder Tips

For example, recently a problem involved finding a somewhat optimal submultiset of a multiset. I of course skipped all good examples and went directly to the biggest one. After all, the big ones are the only interesting ones, right? Wrong! Totally wrong! For that example, only the pure answer was given, in that case the sum of all elements in the submultiset. But in the previous example, which was way smaller (but still quite large), not only the return value, but also the submultiset that achived that result was given. Now guess which example can help understanding the problem better.

Usually TopCoder provides some trivial examples, then some that point out each important goal and then some large magic ones. These people are really nice, so use what they give you! Examples sometimes provide not only the best way to understand a problem, but the only way. Do not underestimate the value of a good example!

 

Sentinels

Sentinels are the second best invention of humankind, only toilet paper is more useful. Ok, I overdo it a bit. What is a sentinel? It's an element that you place at a good strategic position so that you can save some tests. Here's an example with a function that determines whether a key element appears somewhere in an array. The version without sentinel:

bool find ( int a[], int n, int key ) { for( int i=0; i<n; ++i ) if( a[i] == key ) return true; return false;}

The same function with a sentinel:

bool find ( int a[], int n, int key ) { a[n] = key; for( int i=0; ; ++i ) if( a[i] == key ) return (i<n);}

Here a sentinel is introduced by putting the key we search for after the end of the array we search in. This ensures that we *will* eventually find the element. And then when we find it, we only have to check whether we found a real element or just the sentinel. (Thanks isv for making me realize I should explain this example).

Of course this only works if we can use the array spot a[n] to place our sentinel there. But usually you can just make your array larger than you need and the

Page 16: TopCoder Tips

remaining entries are not used, so that's no problem. What's the point of using a sentinel? There are two:

A sentinel can make the program faster.  In the above example, we save the test "i<n" in every loop iteration. However, this is nice in real life, but will not be the reason why you get your program accepted in TopCoder. So forget about this reason!

A sentinel can make the program simpler.  This is not really true for the above example, but you'll see an example in the discussion on functional sentinels. Making a program simpler is good! It's exactly what you want for a programming contest. Why? Because it saves time and you don't get as many chances to add bugs.

Look into "Introduction to Algorithms" (CLRS) for a nice example of sentinels for double-linked lists, where the program really got simpler. If you don't have the book, buy it. It's the new bible for algorithm addicts like us.

Sentinels can appear in many forms. One more example (also found in CLRS): In mergesort, you merge two parts. The common merging always has to look if one part is already finished. By placing a new largest value behind both parts, you can omit this test.

 

Functional Sentinels

In a recent contest, one problem was to determine the winner of a Connect Four game (the real question was somewhat more inflated with details, but that's essentially the task).

What did clever Stefan do? I made the array for the field larger than necessary. This way, I got sentinels to the right and to the bottom of the valid area. To test whether there were four consecutive 1's somewhere, I just started from every position in the real field and walked in each of the three directions (down, right, down+right). I never had to test whether I'm still in the valid range, since elements outside the valid range were no 1's and so my loop stopped at them anyway.

Here's the problem: I forgot about the fourth direction, up+right. Even if I had noticed this mistake before submitting it, it would've involved some thinking to fix it. What would be a fix? Think about it for a moment before you read on.....Ok, one possibility would be to start the real field in the second row of the array, not the first one. This would give me extra sentinels above the field. But then I start indexing at 1 again, which caused a bug in another contest.

Page 17: TopCoder Tips

Here's what I would do now: Make the array exactly as large as needed. Then, never ever directly access its elements. Instead, use the this function:

int f ( int i, int j ) { return (i>=0 && i<n && j>=0 && j<m) ? field[i][j] : -1;}

This way I automatically get sentinels in every invalid position. I'll never have to worry.

Wait a minute! This not only undoes the speed gain we got from using sentinels, but adds an extra function call overhead, too! How stupid would it be to use this? It's not stupid, dammit! Just as the speed gain of sentinels won't make a difference between fast enough and too slow, this speed loss won't make one. After all, few people will use sentinels, so our overhead is only for the function call. But this will not push it over the limit! The problem setters are nice guys. Usually you don't have a chance to get even close to the time limit, unless you're in the totally wrong complexity class.

If you're really worried, then in C++ make "f" a macro instead of a function (or inline? I never used that, don't know). This will also remove the need for having n, m and field globally accessible.

But consider the gain! This will save you a lot of time and headaches! You can still start with index 0, and you don't have to make sure that subsequent calls need an initialization of the array (imagine going from a large field to a smaller one. Then to the right and under the current field, there might be the old values instead of sentinels).

 

Some short advice

You can always assume that the input will have the specified the constraints. If they say that the array contains at least one element, then this will be ensured. If somebody wants to challenge you with invalid input, he won't be able to. TopCoder checks the input before testing your program on it.

Use array indices consistently.  Recently I once again used the indices 0..5 in one part of my program and 1..6 in another part. Generally, this is a bad idea, don't you think? Yes it is, you idiot! Why do I have to tell you this over and over again (Remember that I'm talking to myself).

There are only two reasons to start from 1: The problem statement starts from 1. Bullshit reason! What are you, a whiny coward? Just

Page 18: TopCoder Tips

shift everything by one. The other reason: It actually makes sense, for example if you want to place a sentinel at position 0. But in this case, for sure you won't accidentially forget that you're starting from 1, because the sentinel plays a key part in your code.

If the problem defines a new type, then make it a new type.  Write a class for it. For example, if they come up with "Trilean" values (true, false or maybe), then create a class Trileanwith all needed operations. Using (say) an int to represent such a value will only spread the code for the operations all over the program. Represent it as an int inside the Trilean object.

Use constants with cool names.  In the Trilean example, make up constants TRUE, FALSE and MAYBE. I've actually seen this in lots of programs of higer-rated coders. It can also make the program shorter, but the key benefit is that you can't forget that 2 represents TRUE, not FALSE.

If the problem describes a black box data structure  and its behaviour and asks you to implement that, then create an actual class for it. This will make things so much clearer. Well, of course it always depends on how much overhead you get, same for the Trilean class. But often it's worth it.

Look at the other coders.  How far are they? In the last contest, I was so freaking fast, you could'nt believe it. I had solved all three problems before anyone else in my room had solved his/her second one. In fact, I was way faster than the whole division! Is that great or what? It's "or what"! It's stupid! Instead, I should've taken some time to test my last program better. It was the Connect Four problem, so you already know that I screwed it.

In TopCoder, inputs tend to be small.  So why go for the heavy 30 line solution that gives you O(n lg n) when n never exceeds 50 and there's a 5 line solution with O(n^3)? Don't underestimate the power of modern computers and small inputs.

Have your favourite useful websites ready.  Some suggestions: Java 1.4 API - C++ Reference - C++ Reference C++ Reference

For hard algorithmic problems, have your favourite useful books ready. Some suggestions:

o Introduction to Algorithms  (Cormen, Leiserson, Rivest, Stein)o The Algorithm Design Manual  (Steven Skiena)o Algorithms in C++ (Parts 1-4)  (Robert Sedgewick)o Algorithms in C++ (Part 5)  (Robert Sedgewick) Note that most

reviews are for an old version.

Unfortunately, the 75 minutes of a TopCoder contest are pretty short. So only look into a book if you know what's in it (you don't have the time to read a book) or if you're really desperate.

Page 19: TopCoder Tips

Stefan PochmannLast modified: Thu Dec 12 14:23:35 MET 2002