Programming Contest Strategies
This is a small collection of basic strategies for an effective programming contest team.
Here some quick links:
- Code
- Contests
- Kattis Help
- Example problems:
Basic Rules
Different contests have different rules, but there is typically a common set of rules.
- Teams consist of a few members, normally 3 or fewer.
- Book resources are usually accepted, but absolutely NO internet.
- You will be asked to leave your phone in your room. Pulling it out during the contest could automatically and immediately disqualify your team from the contest.
- Be mindful of which books you bring! Sometimes a discrete math book is helpful. Sometimes an encyclopedia of algorithms (like CLRS) is great.
- One computer, one mouse, one keyboard, one monitor
- All team members must take turns or pair program
- Read in from
stdinand write out everything tostdout(nothing tostderr)- Learn how to use file redirection (
0<, piping with|, etc)
- Learn how to use file redirection (
- Different languages will be given different execution time allotments
- Solutions in different languages will only differ by a constant factor (approximately)
- But keep an eye on complexity!
- Know the runtime complexities of those data structures and algorithms that you are using!
- End your output with a newline
- Some competitions allow for a cheat sheet
Preparing Before the Competition
Practice, practice, practice!
You can get access to many programming contest problems with a quick Google search. There are many online programming contests, for example Project Euler, LeetCode, Kattis, and CodeChef.
Look at previous contests, such as ACM ICPC
Know which languages are acceptable during the competition. Typically the accepted languages include C, C++, Java, and Python 3, but every competition is different.
Important
Be sure you practice for the language version that is available!
For example, Kattis runs Python 3.11.11 (as of 2025.11.23), and Python 3.11's fractions.Fraction does not have __format__ (added only Python 3.12), so formatted prints can by tricky.
If your team is using your own machine, it would be best install and practice on exactly the same version of the language with exactly the same libraries as what is accepted.
Be sure to have a basic familiarity with the following:
- IMPORTANT!!
- Know how to read in from STDIN: ints (positive AND negative), floats/doubles, characters, strings (possibly in delimited characters such as quotes)
- Be aware that the input may need to allow for/ignore multiple spaces
- Know how to use format prints in your language (formatting in Python, formatting in C/C++, formatting in C++ with
cout): left/center/right align (padded), print with leading zeros, fixed digits after decimal, etc. - Convert from string -> int/float and int/float -> string
- Split strings based on a character/delimiter (ex: space) or at an index
- Join list of strings with delimiter
- Mathematics
- Basic statistics, algebra, geometry, trigonometry
- Calculus will sometimes show up in problems
- Often, problems that involve mathematics are really simple to solve, but only if you know the mathematics
- Helper classes
BigIntegerandRatio/Fractionclasses can be life savers! Figure out how to use them in your chosen language. See Simple Arithmetic.
- Most languages (C, C++, Java) require flushing the STDOUT (ex:
std::flush,fflush) if you wantprints to be sent to the tester right away. This is critical if the problem is interactive (ex: Worm Worries | Kattis).
More advanced problems often involve:
- Graph and Tree traversals
- Network Flow (max-flow and min-cut)
- Memoization and Dynamic Programming
- Discrete mathematics (counting, permutations, combinations, bitwise manipulation)
- Knowing how many bits you have to work with and how that affects precision!
- 64bit longs
- 53bit doubles
- etc.
- Knowing that floating point rounding errors happen and how to deal with them
To Bring
- Books
- Language books
- Algorithm books
- Cheat sheets (if allowed)
- Common language features that are difficult to recall under pressure
- String formatting
- Conversion functions:
str2int,str2float
- Scratch paper and pencils
During the Competition
- Read the problem statements very carefully!
- Often the statements will contain very useful hints and very tight or specific constraints
- Inputs will come with bounds. Be sure to test your code at the boundaries, because the judging code will
- Reread the statement multiple times, especially if you get stuck
- IMPORTANT: some problem statements are intentionally obfuscated and filled with red herrings
- Attack the easy problems quickly to rise in rank without incurring too many points
- Be careful! Some easy-looking problems are actually very difficult!
- Do not start coding immediately, but work through the problem on paper
- Not always, but usually when a problem seems easy enough to code on immediately, it actually contains a constraint or hidden edge case that make it a very hard problem
- Pay attention to the constraints on the input
- If the write up states that \(0 \leq N \leq 1000\), you can bet the tester will test values of \(N\) in that entire range, especially \(0\) and \(1000\)!
- Pay attention to the time
- Don't spend too much time on a problem
- Watch the leaderboard.
- If many teams are successfully solving a problem, that problems might be easy to solve.
- If many teams are unsuccessfully attempting a problem, that problem might be secretly very difficult
- Pay attention to the scoring procedure
- In ACM contests, it is always better to solve problems successfully. It is almost always better to work on your solution an extra few minutes to make it correct than to submit an incorrect submission (incurring a large penalty).
- Test your code against ALL of the given test cases
- Do not waste time retyping inputs; instead, create extra test files
- Do not waste time retyping inputs; instead, create extra test files
Cheat Sheet: Starter Code
The following sections contain useful Python 3 code.
Python 3 Starter Code #
Below is a bit of starter code written in Python 3.
You might not need to use all of the code below for every problem, so be sure to understand what each line of code is actually doing.
Warning
input() will throw EOFError if the input "runs out", so make sure you either catch the error or read only what you need to read.
Read Fixed or Known Number of Lines
If the input is fixed or includes a count of things to process or if there is a line indicating the end of the input, then you can use input() to read one line at a time.
As an example of reading in a fixed number of things, the Quadrant Selection | Kattis problem has exactly two lines of input.
As an example of reading in a certain number of things, the first line of input in the Solving for Carrots | Kattis problem contains the number of lines to read in (\(N\)).
As an example of reading until a certain line, the What does the fox say? | Kattis requires you to read and process lines until you read the line what does the fox say?.
N = int(input()) # the first line has a count (N) of lines to read
for i in range(N): # now, read in exactly N lines
line = input() # read one line of text
print(line) # do something with line...
Read Until End of Input
Some problems do not have a specific line that indicates the end of the input, but instead require you to read until the end of the input.
As an example, the Adventures in Moving – Part IV | Kattis problem requires you to read in and process all the lines.
You can still use input() to read in each line, however you must take care!
The input() function will throw an EOFError exception if the input "runs out", so you will need to catch the error.
If you don't catch it, your program will crash, and the competition server might think your solution is incorrect.
The easiest approach is to treat stdin as a stream.
import sys
for line in sys.stdin: # IMPORTANT: line will end with a newline ('\n')
line = line[:-1] # remove '\n' from end
print(line) # do something with line...
Alternatively, you can catch the EOFError error and stop execution then.
try:
while True: # repeate forever (until EOFError)
line = input() # read one line of text
print(line) # do something with line...
except EOFError: pass # we have run out of input
Read All Input First, Then Process Separately
As an alternative to reading in one line at a time, you can read in ALL the lines as a list of strings, and then you can process each line as you like. However, you must take care when indexing into the list!
import sys
#' read in all the lines as a list of strings
#' note: each string has a newline ('\n') at the end! strip it off
lines = [ line.rstrip('\n') for line in sys.stdin ]
#' if you want to strip out and ignore empty lines
lines = [ line for line in lines if line.strip() ]
#' usually first line has the problem's size, so convert it into an int
problem_size = int(lines[0])
#' if you need to exit program quickly, sys.exit() is safe to use
if problem_size == 0:
print('NO SOLUTION')
sys.exit()
#' sometimes a line may contain items separated by spaces. use split()
parts = lines[1].split(' ')
#' finally, print out your solution to STDOUT
print('SOLUTION')
See Kattis Help for starter code snippets for various languages.
Useful Python 3 Code #
The code listing below contains some common Python "recipes" that can be useful.
Conversions
ascii_val = ord('A') # ASCII number of character A is 65
ascii_char = chr(65) # ASCII character of number 65 is A
int_value = int('42') # get int value in string: 42
float_value = float('3.14') # get float value in string: 3.14
str_value = str(42) # convert argument to string: "42"
#' base conversions
#' decimal:42 -> binary:0b101010, octal:0o42, hexadecimal:0x2a
v2, v8, v16 = bin(42), oct(42), hex(42)
#' binary, octal, hexadecimal -> decimal
assert int(v2, 2)==42 and int(v8, 8)==42 and int(v16, 16)==42
#' convert string with things to list of string with things
list_of_strs = '1 2 3'.split() # splits str on spaces ['1', '2', '3']
str_of_list = ' '.join(['1', '2', '3']) # joins list of strs '1 2 3'
list_of_ints = list(map(int, list_of_strs)) # converts to list of ints
Formatted Prints
v = 3.14
print(v) # prints 3.14
#' % printing (similar to C/C++)
print('%f' % v) # prints 3.140000 (0s based on precision of float)
print('%.3f' % v) # prints 3.140 (with 3 digits after decimal)
#' F-string prints
print(f'{v}') # prints 3.14
print(f'{v:.3f}') # prints 3.140 (with 3 digits after decimal)
print('foo', end='') # print without newline
print() # print only newline
Math Functions and Operations
#' Different ways to round #' floor: down. round: to nearest int. ceil: up. int: toward zero from math import floor, ceil # round and int are built-in fns assert floor(-3.9)==-4 and floor(-3.1)==-4 and floor(3.9)==3 # down assert round(-3.9)==-4 and round(-3.1)==-3 and round(3.9)==4 # nearest assert ceil( -3.9)==-3 and ceil( -3.1)==-3 and ceil( 3.9)==4 # up assert int( -3.9)==-3 and int( -3.1)==-3 and int( 3.9)==3 # to 0 print(5 // 2, -5 // 2) # integer division, rounds down print(10 % 3, -10 % 3) # modulus, always non-negative in Python #' Rationals or Fractions: Numerator / Denominator #' use like any other number from fractions import Fraction rat0, rat1 = Fraction(19, 3), Fraction(25, 6) # 19 / 3 and 25 /6 ratsum = rat0 + rat1 # 19/3 + 25/6 = 21/2 print(ratsum) # prints "21 / 2" print(floor(ratsum)) # prints "10" print(ratsum.as_integer_ratio()) # prints "(21, 2)" print(float(ratsum)) # prints "10.5" #' Exponents and Logarithms from math import pow, log print(pow(2, 3)) # 2^3 print(log(3.14)) # log_e 3.14 print(log(3.14) / log(5)) # log_5 3.14, using log-base conversion
Graphs
#' Represent a graph using dictionary with lists
graph = {
'A': ['B', 'C'], # A---B---D
'B': ['A', 'C', 'D'], # \ /
'C': ['A', 'B'], # C
'D': ['B'],
}
#' Breadth-First Search
from collections import deque # deques are efficient queues
path, working = {'C': None}, deque(['C']) # BFS code, starting at C
while working: # keeping track of how we
current = working.popleft() # got there from C
for other in graph[current]:
if other not in path:
path[other] = current
working.append(other)
Lists and Double-Ended Queues (Deques)
names = [
'Alice', 'Zeus', 'Bob', 'Yasmin', 'Carol',
'Xavier', 'Dave', 'Wanda', 'Edith'
]
names.sort() # sort list
some_names = names[1:-2] # get all but first and last
snames = sorted(names, key=lambda name: name[-1]) # sort by last letter
rnames = [name[::-1] for name in names] # reverse names
#' itertools module has a BUNCH of useful functions over lists
from itertools import combinations, permutations
for grp in combinations(names, 2): print(grp) # print all groups of 2
for per in permutations(names, 2): print(per) # print all 2-permutations
#' Double-Ended Queues
from collections import deque
d = deque()
d.appendleft(-1) ; d.append(42) # add LHS (prepend) or RHS (append)
d.popleft() ; d.pop() # pops off left or right
d.extend([2,4]) # extends RHS (keeps order)
d.extendLeft([6,8]) # extends LHS, REVERSE order!
d.rotate(4) # rotates deque right (>0) or left (<0)
Sets
#' Set Manipulations
a_list = ['A','B','A','C','D']
a_set = set(a_list) # will not contain duplicates
b_set = {'A','E','F'}
assert a_set | b_set == {'A','F','D','B','E','C'} # union
assert a_set - b_set == {'B','C','D'} # difference
assert a_set & b_set == {'A'} # intersection
assert a_set ^ b_set == {'B','C','D','E','F'} # symmetric diff
Dictionaries
#' Dictionary
items = "abcdaefghijkalmnopqrsbatuvwxyz"
count = {}
for c in items:
if c in count: count[c] += 1
else: count[c] = 1
#' alternative
count = {}
for c in items:
count[c] = count.get(c, 0) + 1 # default val if key doesn't exist
#' alternative
count = {}
for c in items:
count.setdefault(c, 0) # default val if key doesn't exist
count[c] += 1
#' alternative
from collections import defaultdict
count = defaultdict(lambda:0) # default val if key doesn't exist
for c in items: count[c] += 1
Priority Queues
#' Priority Queues from heapq import heappush, heappop h = [] # heappush and heappop turn a list into priority queue heappush(h, (5, 'write code')) # 1st arg is priority queue heappush(h, (7, 'release product')) # 2nd arg is item that has priority heappush(h, (1, 'write spec')) # in this case, 1st part of tuple heappush(h, (3, 'create tests')) # acts as priority key heappop(h) # (1, 'write spec')
Advanced
#' easy memoization (still must take care with calling order and args)
from functools import cache
@cache
def fibonacci(n):
return n if n <= 1 else fibonacci(n-1) + fibonacci(n-2)
Note
Python will automatically switch to using "Big Integers" if the int value gets too large/small. This means that you do not have to worry about overflow and underflow. Other languages will have a separate type or a module that can do this, but it is built into Python.
Use Caution: big integer arithmetic is much slower than plain int arithmetic! This is especially true with exponents!
Advanced #
The following Bash code will execute your program using sample.in as input and testing the output agaist sample.ans.
If nothing is printed, then success!
Otherwise, something isn't correct.
$ diff <(python3 your_program.py < sample.in) sample.ans
All combinations using bitwise manipulations (source)
uint64_t set_n_bits(int t) { return (1 << (t+1)) - 1; }
uint64_t cycle_combo(uint64_t prev) {
uint64_t t = prev | (prev - 1); // set least sig 0 bits
// set the most significant bit to change
// clear the least significant ones
// add the necassary 1 bits
return (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(prev) + 1));
}
Cheat Sheet: Math Equations #
Sources:
Constants and Approximations
| Symbol | Value* | Description | Python† |
|---|---|---|---|
| \(\pi\) | 3.14159 | Pi | math.pi |
| \(\tau\) | 6.28318 | Tau (twice pi) | math.tau |
| \(\e\) | 2.71828 | Euler's number | math.e |
| \(\sqrt{2}\) | 1.41421 | Square-root of 2 | math.sqrt(2) |
| \(\varphi\) | 1.618033 | Golden Ratio | (1+math.sqrt(5))/2 |
| \(\i\) | \(\sqrt{-1}\) | Imaginary unit | 1j |
*approximate.
†must import math.
Geometry
Area of a Triangle
\[ A = \frac{bh}{2} = rs = \frac{ab}{2} \sin \theta = \frac{abc}{4R} = \sqrt{(s)(s-a)(s-b)(s-c)} \]
Where \(A\) is the area, \(b\) is the base, and \(h\) is the height. In the second equation, \(r\) is the inradius (radius of circle that can be inscribed inside the triangle) and \(s\) is the semiperimeter (which is half the perimeter of triangle). In the third equation, \(\theta\) is the angle between two sides \(a\),\(b\) of the triangle. In the fourth equation, \(a\),\(b\),\(c\) are the sides of the triangle with circumradius \(R\) (radius of circle that passes through all three vertices of triangle). In the final equation (Heron's Formula), \(a\),\(b\),\(c\) are the side lengths of triangle with \(s\) as the semiperimeter.
Pythagorean Theorem and Right Triangles
\[ a^2 + b^2 = c^2 \]
Where \(c\) is the hypotenuse of a right triangle with legs \(a\) and \(b\). Note that there are some "special" right triangles. These include right triangles with angle measures \(45^\circ\)–\(90^\circ\)–\(45^\circ\) and \(30^\circ\)–\(60^\circ\)–\(90^\circ\).
Distance Formula
\[ d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2} \]
Where \((x_1, y_1)\) and \((x_2, y_2)\) are points on a coordinate plane and \(d\) is the distance between them. This is essentially the Pythagorean Theorem restated for points on a plane.
In 3D (where points are \((x_i, y_i, z_i)\)), the distance is
\[ d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2 + (z_2 - z_1)^2} \]
Trigonometry
| Math | Python | Math | Python | |
|---|---|---|---|---|
| \(x=\cos \theta\) | x = math.cos(t) |
\(\theta=\cos^{-1} x = \arccos x\) | t = math.acos(x) |
|
| \(x=\sin \theta\) | x = math.sin(t) |
\(\theta=\sin^{-1} x = \arcsin x\) | t = math.asin(x) |
|
| \(x=\tan \theta\) | x = math.tan(t) |
\(\theta=\tan^{-1} x = \arctan x\) | t = math.atan(x) |
Note
However, use atan2 instead of atan when possible, because it handles quadrants better.
For example: \(\tan^{-1} (y/x)\) is computed as math.atan2(y, x)
Radians and Degrees
| Conversion | Math | Python |
|---|---|---|
| degrees→radians | \(\text{radians} = \text{degrees} \cdot \frac{2\pi}{360}\) | math.radians(d) |
| radians→degrees | \(\text{degrees} = \text{radians} \cdot \frac{360}{2\pi}\) | math.degrees(r) |
Trigonometric Identities
Note that \(\tan \theta = \frac{\sin\theta}{\cos\theta}\). Also \(\sec \theta = \frac{1}{\cos\theta}\) and \(\csc \theta = \frac{1}{\sin \theta}\). Therefore, the identities for \(\tan\), \(\cot\), \(\sec\), \(\csc\) are easily derived from the identities for \(\sin\) and \(\cos\)
Double Angle:
\[ \sin 2\theta = 2\sin\theta\cos\theta \qquad \cos 2\theta = \cos^2\theta - \sin^2\theta \]
Negative Angles:
\[ \cos -\theta = \cos \theta \qquad \sin -\theta = -\sin \theta \]
Pythagorean Identities:
\[ \sin^2 \theta + \cos^2 \theta = 1 \qquad \cot^2 \theta + 1 = \csc^2 \theta \qquad \tan^2 \theta + 1 = \sec^2 \theta \]
Addition / Subtraction Identities:
\[ \sin \alpha + \beta = \sin \alpha \cos \beta + \sin \beta \cos \alpha \qquad \sin \alpha - \beta = \sin \alpha \cos \beta - \sin \beta \cos \alpha \] \[ \cos \alpha + \beta = \cos \alpha \cos \beta - \sin \beta \sin \alpha \qquad \cos \alpha - \beta = \cos \alpha \cos \beta + \sin \beta \sin \alpha \]
Half Angle Identities:
\[ \sin \frac{\theta}{2} = \pm \sqrt{\frac{1 - \cos\theta}{2}} \qquad \cos \frac{\theta}{2} = \pm \sqrt{\frac{1 + \cos\theta}{2}} \]
Longitude and Latitude
The point on a unit sphere given longitude and latitude
\[(x,y,z) = (\cos \theta \cos \phi, \sin\theta \cos\phi, \sin\phi) \]
where \(\phi\) is latitude (\(\phi \in [-90^\circ, 90^\circ]\)) and \(\theta\) is longitude (\(\theta \in [0, 360^\circ) \))
Circle
\[ \text{Area} = \pi r^2 \quad\quad \text{Circumference} = 2 \pi r \]
Arc Length
\[ l = \theta r \]
Where \(l\) is length of arc, \(\theta\) is center angle of the arc in radians, and \(r\) is radius of circle.
Algebra
Quadratic Formula and Discriminant
\[ x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} \]
Where \(a\),\(b\),\(c\) are the coefficients of the \(x^2\), \(x^1\), \(x^0\) terms respectively. If the discriminant (\(d = b^2 - 4ac\)) is \(0\), the quadratic will have one real solution. If the discriminant is positive, the quadratic will have two real solutions. If the discriminant is negative, the quadratic will have no real solutions (only imaginary).
Logarithm Rules
| Logarithmic to Exponential | \( \log_a b = x \Rightarrow a^x = b \) |
| Addition | \( \log_a b + \log_a c = \log_a bc \) |
| Subtraction | \( \log_a b - \log_a c = \log_a \frac{b}{c} \) |
| Exponent Reducing | \( \log_a b^c = c \log_a b\) |
| Change of Base | \( \log_a b = \frac{\log_c b}{\log_c a} \) |
| Reciprocals | \( \log_a b = \frac{1}{\log_b a} \) |
Logarithms in Python
| Math | Python | Details |
|---|---|---|
| \(\log_a b\) | math.log(b, a) |
base defaults to \(\e\) if not given |
| \(a^b\) | math.pow(a, b) |
use when a and b are floats |
| \(a^b\) | pow(a, b) |
use when a and b are ints |
| \(a^b\) | a**b |
similar to built-in pow |
| \(a^b \bmod m\) | pow(a,b,m) |
use when a,b,m are ints |
Discrete
Permutations and Combinations
| Math | Python | Description |
|---|---|---|
| \( _nP_k = \frac{n!}{(n-k)!}\) | math.comb(n, k) |
Number of ways (\(_nP_k\)) to choose \(k\) items out of \(n\) when order matters. |
| \( \binom{n}{k} = \frac{n!}{k!(n-k)!} \) | math.perm(n, k) |
Number of ways (\(\binom{n}{k}\)) to choose \(k\) items out of \(n\) when order does not matter. |
Greatest Common Divisor and Least Common Multiple
| Name | Python |
|---|---|
| Greatest Common Divisor | math.gcd(a, b, c) |
| Least Common Multiple | math.lcm(a, b, c) |
Prime Number
import math
def is_prime(n):
if n <= 1: return False # primes start at 2
if n == 2: return True # first prime
if n % 2 == 0: return False # even numbers >2 are not prime
# not prime if any odd number >=3 up to sqrt(n) divides number
for i in range(3, int(math.sqrt(n)) + 1, 2):
if n % i == 0: return False
return True
Logic
Truth table for negation / not (\(\neg\)), conjunction / and (\(\wedge\)), disjunction / or (\(\vee\)), implication (\(\Rightarrow\)), and equivalence (\(\Leftrightarrow\)).
| \(A\) | \(B\) | \(\neg A\) | \(\neg B\) | \(A \wedge B\) | \(A \vee B\) | \(A \Rightarrow B\) | \(A \Leftrightarrow B\) |
|---|---|---|---|---|---|---|---|
| \(0\) | \(0\) | \(1\) | \(1\) | \(0\) | \(0\) | \(1\) | \(1\) |
| \(0\) | \(1\) | \(1\) | \(0\) | \(0\) | \(1\) | \(1\) | \(0\) |
| \(1\) | \(0\) | \(0\) | \(1\) | \(0\) | \(1\) | \(0\) | \(0\) |
| \(1\) | \(1\) | \(0\) | \(0\) | \(1\) | \(1\) | \(1\) | \(1\) |
Number Theory
Sum of an Arithmetic Series
\[\begin{array}{ccl} \sum_{i=1}^n a_i & = & a_1 + a_2 + \ldots + a_n = \frac{n}{2}(a_1 + a_n) \\ \sum_{x=1}^n x & = & 1 + 2 + \ldots + n = \frac{n(n+1)}{2} \\ \sum_{x=1}^n x & = & 1^2 + 2^2 + \ldots + n^2 = \frac{n(n+1)(2n+1)}{6} \\ \end{array}\]
\[\begin{array}{ccll} \sum_{x=1}^n 2x+1 & = & n^2 & \text{ sum of first } n \text{ positive odd numbers} \\ \sum_{x=1}^n 2x & = & n(n+1) & \text{ sum of first } n \text{ positive even numbers} \\ \end{array}\]
Chinese Remainder Theorem
The Chinese Remainder Theorem (CRT) allows you to solve a system of linear congruences. Let \(m_1\), \(m_2\), ..., \(m_r\) be a collection of pairwise relatively prime integers. Then the system of simultaneous congruences \(x \equiv a_1(\mod m_1)\), \(x \equiv a_2(\mod m_2)\), ..., \(x \equiv a_r( \mod m_r)\) has a unique solution modulo \(M = m_1 m_2, ..., m_r\) for any given integers \(a_1\), \(a_2\), ..., \(a_r\). This is easier to understand in an example and is very well explained in this YouTube video by Cathy Frey.
Fibonacci Numbers
\[ \mathit{Fib}(n) = \begin{cases} 0 & \text{if } n = 0 \\ 1 & \text{if } n = 1 \\ \mathit{Fib}(n-1) + \mathit{Fib}(n-2) & \text{otherwise} \end{cases} \]
- The first few terms are \(0\), \(1\), \(1\), \(2\), \(3\), \(5\), \(8\), \(13\), \(21\), etc.
- The quotient of two consecutive terms approaches the golden ratio: \(\varphi = \frac{1+\sqrt{5}}{2}\).
Factorials
\[ n! = \prod_{x=1}^n x = 1 \cdot 2 \cdot 3 \cdot \ldots \cdot n = \begin{cases} 1 & n = 0 \\ n \cdot (n-1)! & \text{otherwise} \end{cases} \]
Statistics
...
Calculus
estimate integral with sum
...
Example Problems
Below are some example problems with solutions (hidden).
What does the fox say? #
Problem: What does the fox say? | Kattis (2.1)
Try to solve this problem before revealing my solution below.
Solution:
import fileinput
#' load in all of the input
#' note: fileinput.input() returns an iterable, not a list
#' note: each line of iterable includes the `\n` at end
lines = [line[:-1] for line in fileinput.input()]
tests = int(lines[0]) # str->int
i = 1
for test in range(tests):
sounds = lines[i].split(' ') # str->array of str
i += 1
other_sounds = set()
while lines[i] != 'what does the fox say?':
_,_,sound = lines[i].split(' ')
i += 1
other_sounds.add(sound)
i += 1
fox_sounds = [sound for sound in sounds if sound not in other_sounds]
print(' '.join(fox_sounds))
Adventures in Moving – Part IV #
Problem: Adventures in Moving – Part IV | Kattis (4.7)
Try to solve this problem before revealing my solution below.
Solution:
import fileinput
import sys
#' read in and clean up input
lines = [line.rstrip(' \n') for line in fileinput.input()]
lines = [line for line in lines if line.strip()]
#' total distance from Waterloo to big city
total_dist = int(lines[0])
#' fuel stations are next in input
stations = [[int(v) for v in station.split(' ')] for station in lines[1:]]
nstations = len(stations)
#' here is the basic set up:
#' costs[0]: starting point [100] <- cost to get here is 0
#' costs[1]: 0th station [0, 200]
#' costs[2]: 1st station [0, 200]
#' costs[n]: last station [0, 200]
#' costs[n+1]: ending point [100] <- only care about this fuel amount
#' print(costs[n+1][100])
#' data structure to keep track of costs
#' note: could simply keep a single dict of the previous stop rather
#' than storing all of the previous costs!
#' note: using a dictionary so that we can
#' 1. specify exactly where we want to insert values
#' 2. use get() to return a default value if key doesn't exist
#' note: using float('inf') to indicate that a position and fuel
#' amount is impossible to reach (ex: requiring >200L of fuel)
impossible = float('inf')
costs = {}
costs[0] = {}
costs[0][100] = 0
curmarker = 0
for istation in range(nstations):
istop = istation + 1
kmmarker, price = stations[istation]
# compute distance from previous stop to current
dist = kmmarker - curmarker
# start a dict to hold costs for current stop
costs[istop] = {}
for fuel in range(0, 201):
# cost to get to previous stop (burned fuel to get here)
p0 = costs[istop-1].get(fuel+dist, impossible)
# cost to get to current stop but with 1L less of fuel
# (add 1L of fuel)
p1 = costs[istop].get(fuel-1, impossible) + price
# keep whichever is cheaper
costs[istop][fuel] = min(p0, p1)
# note: could skip inserting into costs table if min
# is float('inf')
curmarker = kmmarker # advance our truck to next stop
#' only need to look at a single value in costs table to know
#' the cheapest way to get there!
fuel = 100 # ending condition
dist = total_dist - curmarker
best = costs[nstations].get(fuel+dist, impossible)
#' costs[nstations+1][100] = best # <- don't need to store this, but can
print(best if best != impossible else 'Impossible')
Fridge #
Problem: Fridge | Kattis (3.1)
Try to solve this problem before revealing my solution below.
Solution:
#!/usr/bin/python3
import fileinput
import sys
lines = [line.rstrip(' \n') for line in fileinput.input()]
lines = [line for line in lines if line.strip()]
line = lines[0] # only care about first line of input
#' if mincount == 0, then we can only produce single digit numbers, and
#' min key with val==0 is the answer (except X=0 => 10)
#' if mincount == 1, then XX is a 2-digit number that we cannot produce,
#' and the answer is X=min key with val==1 (except for X=0 =>100)
#' if mincount == 2, then XXX is a 3-digit number ...
#' so, the general answer is:
#' - XX...X where X is smallest digit with smallest count, except for
#' - 100...0 if smallest digit with smallest count is 0
#' count number of each magnet digits
magnet_counts = { i:line.count(i) for i in '0123456789' }
#' find which magnet digit(s) we have least number
#' note: might have multiple, so find all digits with min count
min_count = min(magnet_counts.values())
min_digits = list(sorted(
k for (k,v) in magnet_counts.items() if v == min_count
))
#' 0 always "lags" behind other digits, so handle it specially
if min_digits == ['0']:
# 0 is the only digit, so first number we cannot produce
# will be in form 10...0
print('1' + '0' * (min_count+1))
else:
# find smallest non-0 digit
# if 0 is in min_digits, then use index 1
# otherwise, use index 0
idx = 1 if '0' in min_digits else 0
print(min_digits[idx] * (min_count+1))
Simple Arithmetic #
Problem: Simple Arithmatic | Kattis (1.2–4.4)
Try to solve this problem before revealing my solution below.
Solution:
#!/usr/bin/python3
from math import floor
from fractions import Fraction
a, b, c = map(int, input().split(' '))
a = Fraction(a, 1)
b = Fraction(b, 1)
c = Fraction(c, 1)
v = a * b / c
#' Kattis uses Python 3.8 (https://open.kattis.com/languages/python3)
#' which means that Fraction does not have `__format__`. so, need
#' to separate integer from decimal explicitly
iv = floor(v)
dv = (v - Fraction(iv, 1)) * Fraction(1000000, 1)
print(f'{iv}.{floor(dv):06d}')