🚀 Essential C++ Templates for Competitive Programming 🚀
Mastering competitive programming requires not only a deep understanding of algorithms and data structures but also efficiency in implementing them during contests. Using template-based coding techniques can save valuable time and help you focus on problem-solving. Here's a collection of commonly used C++ templates that every competitive programmer should have in their toolkit.
1️⃣ Basic Competitive Programming Template
The foundation for most competitive programming solutions starts with a clean, fast I/O setup and common utility definitions.
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define fastio ios_base::sync_with_stdio(false); cin.tie(0);
const int MOD = 1e9 + 7;
int main() {
fastio; // Fast input/output setup
// Start coding your solution here
return 0;
}
Key Highlights:
2️⃣ Modulo Arithmetic
In many problems, you are asked to work with large numbers and return answers modulo a given constant (e.g., 1e9+7). Here's a simple template for modulo arithmetic.
ll mod_add(ll a, ll b) { return (a + b) % MOD; }
ll mod_sub(ll a, ll b) { return (a - b + MOD) % MOD; }
ll mod_mul(ll a, ll b) { return (a * b) % MOD; }
ll mod_pow(ll a, ll b) {
ll res = 1;
while (b > 0) {
if (b & 1) res = mod_mul(res, a);
a = mod_mul(a, a);
b >>= 1;
}
return res;
}
Why It's Useful:
3️⃣ Binary Search Algorithm
Binary search is one of the most efficient algorithms for searching in sorted arrays. It’s a must-have template for competitive programmers.
int binary_search(vector<int>& arr, int target) {
int low = 0, high = arr.size() - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) return mid; // Target found
if (arr[mid] < target) low = mid + 1;
else high = mid - 1;
}
return -1; // Target not found
}
Where to Use:
4️⃣ Sieve of Eratosthenes (Prime Number Generation)
Sieve of Eratosthenes is an efficient algorithm to generate all prime numbers up to a given number n.
vector<bool> sieve(int n) {
vector<bool> is_prime(n + 1, true);
is_prime[0] = is_prime[1] = false;
for (int i = 2; i * i <= n; i++) {
if (is_prime[i]) {
for (int j = i * i; j <= n; j += i) {
is_prime[j] = false; // Mark multiples as non-prime
}
}
}
return is_prime;
}
Use Case:
5️⃣ Union-Find (Disjoint Set Union - DSU)
Union-Find is a crucial data structure for dynamic connectivity problems. It’s perfect for tasks like detecting cycles, connected components, and more.
Recommended by LinkedIn
class UnionFind {
vector<int> parent, rank;
public:
UnionFind(int n) {
parent.resize(n);
rank.resize(n, 1);
for (int i = 0; i < n; i++) parent[i] = i;
}
int find(int u) {
if (u == parent[u]) return u;
return parent[u] = find(parent[u]); // Path compression
}
void unite(int u, int v) {
int root_u = find(u);
int root_v = find(v);
if (root_u != root_v) {
if (rank[root_u] > rank[root_v]) parent[root_v] = root_u;
else if (rank[root_u] < rank[root_v]) parent[root_u] = root_v;
else {
parent[root_v] = root_u;
rank[root_u]++;
}
}
}
};
Where to Apply:
6️⃣ Dynamic Programming (0/1 Knapsack)
The 0/1 Knapsack problem is one of the most classic dynamic programming problems. The following template solves the problem in O(n * W) where n is the number of items and W is the capacity of the knapsack.
int knapsack(vector<int>& weights, vector<int>& values, int W) {
int n = weights.size();
vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));
for (int i = 1; i <= n; i++) {
for (int w = 0; w <= W; w++) {
if (weights[i - 1] <= w) {
dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]);
} else {
dp[i][w] = dp[i - 1][w];
}
}
}
return dp[n][W]; // Max value we can carry
}
When to Use:
7️⃣ Topological Sort (Kahn’s Algorithm)
Topological sort is used for problems involving task scheduling, dependency resolution, or any problem based on Directed Acyclic Graphs (DAGs).
vector<int> topological_sort(vector<vector<int>>& adj) {
int n = adj.size();
vector<int> in_degree(n, 0), topo_sort;
queue<int> q;
// Calculate in-degree of all vertices
for (int i = 0; i < n; i++) {
for (int v : adj[i]) {
in_degree[v]++;
}
}
// Add vertices with in-degree 0 to the queue
for (int i = 0; i < n; i++) {
if (in_degree[i] == 0) q.push(i);
}
// Process vertices
while (!q.empty()) {
int u = q.front();
q.pop();
topo_sort.pb(u);
for (int v : adj[u]) {
in_degree[v]--;
if (in_degree[v] == 0) q.push(v);
}
}
return topo_sort;
}
Why It’s Important:
8️⃣ Trie for Prefix-Based Search
Tries (prefix trees) are highly efficient for solving string-based problems, especially those involving prefix searches or dictionary lookups.
struct TrieNode {
TrieNode* children[26];
bool isEndOfWord;
TrieNode() {
isEndOfWord = false;
for (int i = 0; i < 26; i++) children[i] = nullptr;
}
};
class Trie {
TrieNode* root;
public:
Trie() { root = new TrieNode(); }
void insert(string word) {
TrieNode* node = root;
for (char c : word) {
int index = c - 'a';
if (!node->children[index]) node->children[index] = new TrieNode();
node = node->children[index];
}
node->isEndOfWord = true;
}
bool search(string word) {
TrieNode* node = root;
for (char c : word) {
int index = c - 'a';
if (!node->children[index]) return false;
node = node->children[index];
}
return node->isEndOfWord;
}
};
Use Case:
These are just a few of the must-know C++ templates for competitive programming. Whether you're aiming to speed up your submissions or sharpen your problem-solving efficiency, having these templates at your disposal can make a significant difference.
🔗 #CompetitiveProgramming #CPlusPlusTemplates #CodingEfficiency #AlgorithmTemplates
This template-based approach can streamline your coding process in contests, giving you more time to focus on solving