I decided to share the way in which I have set up my competitive programming environment, as I think there are quite a few cool things to share here. I will focus more on my reasoning for doing things my way than the implementation details (though there is a link to all the code at the end of the blog post).
Firstly the boring stuff: I use Ubuntu, write my programs in VSCode, and compile and run them with the in-built terminal. There is nothing fancy here, except that I have a snippet which I invoke whenever I create a new C++ file. Now the snippet itself is a little more interesting.
My code template
#include <iostream>
#include <iomanip>
#include <iterator>
#include <cstring>
#include <type_traits>
#include <vector>
#include <deque>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <stack>
#include <list>
#include <string>
#include <bitset>
#include <algorithm>
#include <cmath>
#include <random>
#include <cassert>
#include <ctime>
#include <ratio>
#include <functional>
#include <sstream>
using namespace std;
#define pb push_back
#define fi first
#define se second
typedef int _def;
#define fori(a) for(_def i=0; i<(a); i++)
#define fori1(a) for(_def i=1; i<=(a); i++)
#define fori_(a) for(_def i=(a)-1; i>=0; i--)
#define fori1_(a) for(_def i=(a); i>0; i--)
#define forii(a, b) for(_def i=(a); i<(b); i++)
#define forii_(a, b) for(_def i=(b)-1; i>=(a); i--)
#define forj(a) for(_def j=0; j<(a); j++)
#define forj1(a) for(_def j=1; j<=(a); j++)
#define forj_(a) for(_def j=(a)-1; j>=0; j--)
#define forj1_(a) for(_def j=(a); j>0; j--)
#define forjj(a, b) for(_def j=(a); j<(b); j++)
#define forjj_(a, b) for(_def j=(b)-1; j>=(a); j--)
#define fork(a) for(_def k=0; k<(a); k++)
#define fork1(a) for(_def k=1; k<=(a); k++)
#define fork_(a) for(_def k=(a)-1; k>=0; k--)
#define fork1_(a) for(_def k=(a); k>0; k--)
#define forkk(a, b) for(_def k=(a); k<(b); k++)
#define forkk_(a, b) for(_def k=(b)-1; k>=(a); k--)
#define forl(a) for(_def l=0; l<(a); l++)
#define forl1(a) for(_def l=1; l<=(a); l++)
#define forl_(a) for(_def l=(a)-1; l>=0; l--)
#define forl1_(a) for(_def l=(a); l>0; l--)
#define forll(a, b) for(_def l=(a); l<(b); l++)
#define forll_(a, b) for(_def l=(b)-1; l>=(a); l--)
#define forg(a) for(_def g=0; g<(a); g++)
#define forg1(a) for(_def g=1; g<=(a); g++)
#define forg_(a) for(_def g=(a)-1; g>=0; g--)
#define forg1_(a) for(_def g=(a); g>0; g--)
#define forgg(a, b) for(_def g=(a); g<(b); g++)
#define forgg_(a, b) for(_def g=(b)-1; g>=(a); g--)
#define forf(a) for(_def f=0; f<(a); f++)
#define forf1(a) for(_def f=1; f<=(a); f++)
#define forf_(a) for(_def f=(a)-1; f>=0; f--)
#define forf1_(a) for(_def f=(a); f>0; f--)
#define forff(a, b) for(_def f=(a); f<(b); f++)
#define forff_(a, b) for(_def f=(b)-1; f>=(a); f--)
#define forh(a) for(_def h=0; h<(a); h++)
#define forh1(a) for(_def h=1; h<=(a); h++)
#define forh_(a) for(_def h=(a)-1; h>=0; h--)
#define forh1_(a) for(_def h=(a); h>0; h--)
#define forhh(a, b) for(_def h=(a); h<(b); h++)
#define forhh_(a, b) for(_def h=(b)-1; h>=(a); h--)
#define fastIO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define endl '\n'
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
template <typename T, typename U>
ostream& operator<<(ostream& out, const pair<T, U> & p) {
out << '{' << p.fi << ':' << p.se << '}';
return out;
}
template <template <typename, typename...> class Container,
typename Value,
typename... AddParams,
typename std::enable_if<!std::is_same<Container<Value, AddParams...>,std::string>::value>::type* = nullptr >
ostream& operator<<(ostream& out, const Container<Value, AddParams...> & container) {
out << '{';
bool f = true;
for(auto &i: container){
if(!f) out << ", ";
else f = false;
out << i;
}
out << '}';
return out;
}
#ifdef CP_DEBUG_
#define debug(...) cerr<<"dbg("; _debug(#__VA_ARGS__, __VA_ARGS__)
#else
#define debug(...)
#endif
template <typename Arg1>
void _debug(const char* name, Arg1&& arg1){
while(*name == ' ' || *name == ',')++name;
cerr << name << " : " << arg1 << ')' << endl;
}
template <typename Arg1, typename... Args>
void _debug(const char* names, Arg1&& arg1, Args&&... args){
int depth = 0;
string variable;
while(*names == ' ' || *names == ',')++names;
while(*names != ',' || depth){
if(*names == '[' || *names == '{' || *names == '(')depth++;
if(*names == ']' || *names == '}' || *names == ')')depth--;
variable += *names;
++names;
}
while(variable.back() == ' ')variable.pop_back();
cerr << variable << " : " << arg1 << " | " ;
_debug(names, args...);
}
const int N = 1e6+10;
//const ll M = 1e9+7;
int main(){
fastIO;
}
The obvious
I will start with the standard parts that can be found in one form or another in pretty much every competitive programming template.
using namespace std;
There is no reason to not have this line in your competitive programming template. You will use a lot of standard library functionality, and you want to minimize the number of characters you need for each of them.
fastIO
#define fastIO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define endl '\n'
This is a standard way to make cin
and cout
(almost) as fast as scnaf / printf. This basically avoids synchronizing different streams between each call of cin or cout. However, we can still make them synchronize with cerr
, which is useful when debugging.
The second line is also important, as endl
will flush the ouput immediately, slowing down the program, whereas '\n'
won’t.
Note: for interactive problems we actually want to flush the output immediately, so for such problems the second line should be commented out.
To make this work I simply add fastIO;
at the start of main
.
Shortened common constructs
#define pb push_back
#define fi first
#define se second
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
These are very common attributes / constructs to use in competitive programming, so it is useful to shorten them.
The first line is for working with vectors, the next 2 for working with pairs, and the remaining are shorthand names for common variable types. People will often have different ways to shorten and will disagree on what to shorten, but there is nothing out of the ordinary here.
For loop macros
Here we arrive at something that I do differently than most competitive programmers. It is fairly standard practice to shorten loop names with a macro such as rep(i, a, b)
, which will usually be expanded to for(int i=a; i<b; i++)
. Now I found this unsatisfactory for several reasons:
- The macro is not actually that much shorter
- Very often
a
will be 0 or 1, and writing out 0 or 1 every single time is not very productive. - I pretty much never need more than a few for-loop indices, so writing out
i
orj
with a comma every single time is not very productive. - This construct does not allow me to iterate in reverse. Although not very common, it is nice to have a way to do so when needed.
So here I propose a solution to solve the above problems. For every loop variable that I feel I use often enough (and a few more for good measure), I create the following macros (example creates them for variable i
):
// from 0 to a-1
#define fori(a) for(_def i=0; i<(a); i++)
// from 1 to a
#define fori1(a) for(_def i=1; i<=(a); i++)
// from a to b-1
#define forii(a, b) for(_def i=(a); i<(b); i++)
// The 3 above, just in reverse
#define fori_(a) for(_def i=(a)-1; i>=0; i--)
#define fori1_(a) for(_def i=(a); i>0; i--)
#define forii_(a, b) for(_def i=(b)-1; i>=(a); i--)
Now the large number of macros does somewhat slow down compilation time. That being said, I found these conventions extremely useful and intuitive. It also just looks nicer, especially when writing nested loops. With one glance you can immediately tell what they’re doing, how many times the loop is run, and there can be no silly mistakes left behind (like writing a reverse for loop, but incrementing the loop counter instead of decrementing).
The debug function
Almost all competitive programming problems are so small that it makes sense to just dump a bunch of output for debugging instead of using a proper debugger. The debug
function allows for this ouput to be dumped nicely.
This is by no means a new concept. In fact, my debug function is based on the ones presented here and here, but I have made a couple key improvements:
template <typename T, typename U>
ostream& operator<<(ostream& out, const pair<T, U> & p) {
out << '{' << p.fi << ':' << p.se << '}';
return out;
}
template <template <typename, typename...> class Container,
typename Value,
typename... AddParams,
typename std::enable_if<!std::is_same<Container<Value, AddParams...>,std::string>::value>::type* = nullptr >
ostream& operator<<(ostream& out, const Container<Value, AddParams...> & container) {
out << '{';
bool f = true;
for(auto &i: container){
if(!f) out << ", ";
else f = false;
out << i;
}
out << '}';
return out;
}
Above I define a concise way to print pairs (in the first function) and collection types (in the second function).
Note that this can be used not just by the debug function, but by any ostream
operator like cout
and cerr
, so it is useful on its own as well!
#ifdef CP_DEBUG_
#define debug(...) cerr<<"dbg("; _debug(#__VA_ARGS__, __VA_ARGS__)
#else
#define debug(...)
#endif
Above code defines the debug macro. The important thing is that the debug function does something only if the flag CP_DEBUG_
is defined. Since it will not be defined when compiling on the online judge, it will not generate unnecessary output, and hence will not slow down the program. This is great, since we don’t need to comment out any debug statements before submitting the solution to the online judge!
See the section about compilation aliases below for how to define CP_DEBUG_
during compilation.
Additionally I make sure to enclose any output from a debug statement in dbg()
, so as to clearly indicate that it came form a debug statement. Also the _debug
function that does the printing gets both the string containing comma separated variable names, and the values of the variables.
template <typename Arg1>
void _debug(const char* name, Arg1&& arg1){
while(*name == ' ' || *name == ',')++name;
cerr << name << " : " << arg1 << ')' << endl;
}
template <typename Arg1, typename... Args>
void _debug(const char* names, Arg1&& arg1, Args&&... args){
int depth = 0;
string variable;
while(*names == ' ' || *names == ',')++names;
while(*names != ',' || depth){
if(*names == '[' || *names == '{' || *names == '(')depth++;
if(*names == ']' || *names == '}' || *names == ')')depth--;
variable += *names;
++names;
}
while(variable.back() == ' ')variable.pop_back();
cerr << variable << " : " << arg1 << " | " ;
_debug(names, args...);
}
Finally above we can see the use of variadic functions to print out the variables in the following format:
var_name1 : var_value1 | var_name2 : var_value2 | ...
In my opinion, it is a lot easier to read the debug output when the variable names are next to their values. Additionally, I keep track of how many opening and closing brackets we encountered in order to split on the correct comma. That being said, I cannot do that for angle brackets <>
that are used in templates, as it is difficult to distinguish them from <
and >
operators. A quick workaround is to enclose the whole expression inside a pair of parentheses when using commas inside angle brackets.
Includes
This is a quick one, but I wanted to cover it anyways. Many competitive programmers might be asking: why so many includes? Why not just add a single #include <bits/stdc++.h>
and call it a day?
There really isn’t much difference between the 2 approaches if the programmer makes sure to include all the modules that they might need… apart from compilation speed. There are many headers that can never be useful in a competitive programming competition, and processing those headers every time you compile your program is wasteful. In competitive programming any saved second can be worth points, and since I’m not sacrificing anything in the process, I choose to have a million includes.
An unintended consequence is that I actually know more of the useful features that are available in the C++ standard library, as I carefully went through all the modules and looked if there’s anything useful in them!
Compilation aliases
In addition to the above template, which can be invoked with a snippet in VSCode, I have the following lines in my .bash_aliases
file:
cp_flags="-DCP_DEBUG_ -O2 -Wall -Wextra -Wshadow -fsanitize=undefined -std=c++11"
for x in {a..z}
do
alias g++$x="g++ $cp_flags -o $x"
done
This does a fairly simple thing: it allows me to quickly compile a program with a bunch of flags that show warnings, set C++ version, optimize the program, and specify any single letter output file path. In addition, it defines CP_DEBUG_
, which toggles whether the previously mentioned debug statements print anything.
In particular, writing g++a source_file_name.cpp
will compile my program into the executable called a
, which can be run with ./a
. Similarly for g++b
and others.
Apart from the obvious that I need to type fewer characters to compile my programs, and get all the warning flags to inform me of shadowed variables, it is extremely useful to be able to compile programs into different files. In competitions you will very often have problems labeled as A, B, C and so on. Compiling problem A to executable a, and problem B to executable b will make it difficult to mix up which executable is for which problem. I personally don’t call my problems A.cpp
, B.cpp
… but if someone did, they could go one step further, and include the file name in the alias as well to a have a fully automated approach.
Additionally sometimes you will want to compile test files, generators, and so on, which is why it’s nice to have the whole alphabet of output files available with these commands.
Conclusion
I find that competitive programming setup is quite personal for many people, and what works for me won’t necessarily work for other people. Feel free to pick out the parts that you find appealing in my approach, and build on top of them! You can find all the code, as well as the VSCode snippet here.