Reusable C++ Templates for Fast I/O, Modular Arithmetic, and String Data Structures

Competitive programming demands a high degree of code reusability. Below is a curated set of templates that have been fine-tuned for typical on line judges, including a comprehensive header, fast input/output routines, a modular arithmetic wrapper, and implementations of the suffix automaton and suffix array.

Compact Header with Utilities

namespace cp_core {
#ifndef ONLINE_JUDGE
    #define LOCAL_BUILD
    #define FILE_REDIRECT
#endif
    #define ENABLE_FAST_IO

#ifdef ENABLE_FAST_IO
    char io_buf[1 << 20], *read_ptr = io_buf, *write_ptr = io_buf;
    #define next_char() (read_ptr == write_ptr && (write_ptr = (read_ptr = io_buf) + fread(io_buf, 1, 1 << 20, stdin)) ? EOF : *read_ptr++)
#else
    #define next_char() getchar()
#endif

    using i64 = long long;
    using u64 = unsigned long long;
    using f64 = double;
    using ld = long double;
    using pii = std::pair<int, int>;

#ifdef FILE_REDIRECT
    struct FileRedirect {
        FileRedirect(const std::string &problem) {
            freopen((problem + ".in").c_str(), "r", stdin);
            freopen((problem + ".out").c_str(), "w", stdout);
        }
    } redirect_instance("problem");
#endif

#define pub push_back
#define pob pop_back

    template<typename T>
    std::ostream& operator<<(std::ostream &os, const std::vector<T> &vec) {
        if (vec.empty()) return os << "{}";
        os << '{' << vec.front();
        for (std::size_t i = 1; i < vec.size(); ++i) os << ',' << vec[i];
        return os << '}';
    }

    template<typename T> void set_min(T &a, T b) { if (a > b) a = b; }
    template<typename T> void set_max(T &a, T b) { if (a < b) a = b; }

    template<typename T>
    void log_value(const char *label, T value) {
#ifdef LOCAL_BUILD
        std::cerr << label << '=' << value << '\n';
#endif
    }

    template<typename T, typename... Ts>
    void log_value(const char *label, T first, Ts... rest) {
#ifdef LOCAL_BUILD
        while (*label != ',') std::cerr << *label++;
        std::cerr << '=' << first << ',';
        log_value(label + 1, rest...);
#endif
    }

#define LOG(...) log_value(#__VA_ARGS__, __VA_ARGS__)

    template<typename T = int>
    T scan() {
        char c = next_char(); bool negative = false; T x = 0;
        while (c < 48 || c > 57) { if (c == '-') negative = true; c = next_char(); }
        for (; c >= 48 && c <= 57; c = next_char()) x = (x << 1) + (x << 3) + (c ^ 48);
        return negative ? -x : x;
    }

    template<typename T>
    void scan(T &x) {
        char c = next_char(); bool negative = false; x = 0;
        while (c < 48 || c > 57) { if (c == '-') negative = true; c = next_char(); }
        for (; c >= 48 && c <= 57; c = next_char()) x = (x << 1) + (x << 3) + (c ^ 48);
        if (negative) x = -x;
    }

    template<typename T, typename... Ts>
    void scan(T &first, Ts&... rest) { scan(first); scan(rest...); }
}

Modular Arithmetic (modint)

A lightweight wrapper that supports addition, subtraction, multiplication, and division under a global modulus MOD.

constexpr int MOD = 1e9 + 7;

struct ModInt {
    int value;
    ModInt(int x = 0) : value(x % MOD + (x < 0) * MOD) {}

    ModInt operator+(const ModInt &o) const { return (value + o.value) % MOD; }
    ModInt operator-(const ModInt &o) const { return (value - o.value + MOD) % MOD; }
    ModInt operator*(const ModInt &o) const { return static_cast<long long>(value) * o.value % MOD; }
    ModInt operator/(const ModInt &o) const {
        int exponent = MOD - 2;
        ModInt result{1}, base = o;
        while (exponent) {
            if (exponent & 1) result = result * base;
            base = base * base;
            exponent >>= 1;
        }
        return *this * result;
    }

    ModInt operator-() const { return MOD - value; }

    ModInt& operator+=(const ModInt &o) { return *this = *this + o; }
    ModInt& operator-=(const ModInt &o) { return *this = *this - o; }
    ModInt& operator*=(const ModInt &o) { return *this = *this * o; }
    ModInt& operator/=(const ModInt &o) { return *this = *this / o; }

    bool operator==(const ModInt &o) const { return value == o.value; }
    bool operator!=(const ModInt &o) const { return value != o.value; }
};

Simple Integer Readers

Two classic handwritten parsers: one for unsigned inputs and one that detects a leading minus sign.

int read_int() {
    char c; while ((c = getchar()) < 48 || c > 57);
    int x = 0;
    do { x = (x << 1) + (x << 3) + (c ^ 48); } while ((c = getchar()) >= 48 && c <= 57);
    return x;
}

int read_signed_int() {
    char c; while ((c = getchar()) < 48 || c > 57) { if (c == '-') break; }
    bool negative = false;
    if (c == '-') { negative = true; c = getchar(); }
    int x = 0;
    do { x = (x << 1) + (x << 3) + (c ^ 48); } while ((c = getchar()) >= 48 && c <= 57);
    return negative ? -x : x;
}

Fast I/O with Custom Buffer

By bypassing standard library buffering we achieve faster parsing.

#define CIN_CHAR() (p1 == p2 && (p2 = (p1 = cin_buf) + fread(cin_buf, 1, 1 << 21, stdin)) ? EOF : *p1++)
char cin_buf[1 << 21], *p1 = cin_buf, *p2 = cin_buf;

int fast_read() {
    char c = CIN_CHAR();
    while (c < 48 || c > 57) c = CIN_CHAR();
    int x = 0;
    do { x = (x << 1) + (x << 3) + (c ^ 48); c = CIN_CHAR(); } while (c >= 48 && c <= 57);
    return x;
}

int fast_read_signed() {
    char c = CIN_CHAR(); bool neg = false;
    while (c < 48 || c > 57) { if (c == '-') neg = true; c = CIN_CHAR(); }
    int x = 0;
    do { x = (x << 1) + (x << 3) + (c ^ 48); c = CIN_CHAR(); } while (c >= 48 && c <= 57);
    return neg ? -x : x;
}

Suffix Automaton

A compact suffix automaton that computes end‑position cardinalities for each state.

#include <cstdio>
#include <cstring>
using namespace std;

const int MAXN = 1000003;
char str[MAXN];
int nxt[MAXN][26], len[MAXN], link[MAXN], cnt[MAXN];
int bucket[MAXN], order[MAXN];
int last = 1, nodes = 1, n;

void sam_extend(int ch) {
    int cur = ++nodes, p = last;
    len[cur] = len[p] + 1;
    cnt[cur] = 1;
    while (p && !nxt[p][ch]) { nxt[p][ch] = cur; p = link[p]; }
    if (!p) { link[cur] = 1; last = cur; return; }
    int q = nxt[p][ch];
    if (len[q] == len[p] + 1) { link[cur] = q; last = cur; return; }
    int clone = ++nodes;
    len[clone] = len[p] + 1;
    link[clone] = link[q];
    memcpy(nxt[clone], nxt[q], sizeof(nxt[0]));
    link[q] = link[cur] = clone;
    while (p && nxt[p][ch] == q) { nxt[p][ch] = clone; p = link[p]; }
    last = cur;
}

void build_sam() {
    scanf("%s", str);
    n = strlen(str);
    for (int i = 0; i < n; ++i) sam_extend(str[i] - 'a');
    for (int i = 1; i <= nodes; ++i) ++bucket[len[i]];
    for (int i = 1; i <= n; ++i) bucket[i] += bucket[i - 1];
    for (int i = nodes; i; --i) order[bucket[len[i]]--] = i;
    for (int i = nodes; i; --i) {
        int node = order[i];
        cnt[link[node]] += cnt[node];
    }
}

Suffix Array (O(n log n) prefix doubling)

An in‑place implementation of the prefix‑doubling algorithm that computes the suffix array, rank array, and LCP array without extra sorting.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 200003;
char s[N];
int n, w, p;
int buc[N], sa[N], rk[N], old_rk[N << 1], tmp[N];
int lcp[N];

bool same_rank(int a, int b) {
    return old_rk[a] == old_rk[b] && old_rk[a + w] == old_rk[b + w];
}

void build_sa(int alphabet) {
    memset(buc + 1, 0, alphabet << 2);
    for (int i = 1; i <= n; ++i) ++buc[rk[i] = s[i]];
    for (int i = 1; i <= alphabet; ++i) buc[i] += buc[i - 1];
    for (int i = n; i; --i) sa[buc[rk[i]]--] = i;

    for (w = 1, p = 0; ; w <<= 1, p = 0) {
        for (int i = n; i > n - w; --i) tmp[++p] = i;
        for (int i = 1; i <= n; ++i) if (sa[i] > w) tmp[++p] = sa[i] - w;

        memset(buc + 1, 0, alphabet << 2);
        for (int i = 1; i <= n; ++i) ++buc[rk[tmp[i]]];
        for (int i = 1; i <= alphabet; ++i) buc[i] += buc[i - 1];
        for (int i = n; i; --i) sa[buc[rk[tmp[i]]]--] = tmp[i];

        memcpy(old_rk + 1, rk + 1, n << 2);
        p = rk[sa[1]] = 1;
        for (int i = 2; i <= n; ++i) {
            rk[sa[i]] = same_rank(sa[i], sa[i - 1]) ? p : ++p;
        }
        if (p == n) break;
        alphabet = p;
    }

    for (int i = 1, k = 0; i <= n; ++i) {
        if (rk[i] == 1) { k = 0; continue; }
        if (k) --k;
        while (i + k <= n && sa[rk[i] - 1] + k <= n && s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
        lcp[rk[i] - 1] = k;
    }
}

Tags: C++ Competitive Programming Templates fast I/O modint

Posted on Fri, 08 May 2026 16:06:53 +0000 by infestedarch0n