マイ競プロ用テンプレート

競技プログラミングでは,コードを記述する「速さ」と「正確さ」が求められます。 そのため,競プロerの多くは自前のマクロやエイリアスなど用意し,コード記述をしやすくする工夫を行っています。

今回は私のマイテンプレート (C++) を紹介します。

#include <bits/stdc++.h>
#define REP(i,n)   for(int i=0;i<(int)(n);++i)
#define FOR(i,l,r) for(int i=(int)(l);i<(int)(r);++i)
#define ALL(v)     (v).begin(),(v).end()
using llong = long long;
using vi    = std::vector<int>;
using vvi   = std::vector<vi>;
using pii   = std::pair<int,int>;
using namespace std;
constexpr int       INF  = 1e9;
constexpr long long LINF = 1e18;
constexpr double    EPS  = 1e-10;
constexpr int       MOD  = 998'244'353;
constexpr int       MOD2 = 1e9+7;

template <typename Type>
std::istream &operator>>(std::istream &is, std::vector<Type> &v) {
    for(auto &in : v) is >> in;
    return is;
}

template <typename Type>
std::ostream &operator<<(std::ostream &os, const std::vector<Type> &v) {
    for(auto itr = v.cbegin(); itr != v.cend(); ++itr) os << (itr == v.cbegin() ? "" : " ") << *itr;
    return os;
}

#ifdef DEBUG

#include "debug.hpp"
using namespace algorithm;

#else

#define debug(...) static_cast<void>(0)

#endif

int main(){}

ライブラリ

#include <bits/stdc++.h>
using namespace std;

<bits/stdc++.h> の中身はこちらのようになっており,簡単に言うと「標準ライブラリ全部載せ」です。 GCC が提供しているもので,他の環境(Clang など)では動きません。 移植性などの問題を抱える邪道ライブラリですが,「コードがすっきりする」という理由で使ってます。

「using namespace std;」1名前空間の修飾を省略するものです。 普段の開発では名前衝突が懸念されますが,タイプ量を減らすために記述しています。

REPマクロ

#define REP(i,n)   for(int i=0;i<(int)(n);++i)
#define FOR(i,l,r) for(int i=(int)(l);i<(int)(r);++i)

競プロ界隈では有名なマクロです。

for文は利用場面が多いですが,3つ式を書く必要があり,記述量が多くバグの温床です。 例えば,次のような記述ミスはコンパイル時にエラーがでず,発見しづらいバグとなります。

for(int i=0;i<n;++i){
    for(int j=0;j<m;++i){  // 更新式の変数をiになっている! 無限ループに...
        ...
    }
}

REPマクロは,変数を一回しか書く必要がないため,そのようなミスを防ぐことができます。

REP(i,n)REP(j,m){
    ...
}

ALLマクロ

#define ALL(v) (v).begin(),(v).end()

これもよく使われているマクロです。

std::sort() や std::lower_bound() の STL のコンテナの先頭と末尾のイテレータを指定するときに用います。

vector<int> v({3, 9, 6, 1, 2, 12, 30, 15});
sort(ALL(v));
int num = lower_bound(ALL(v), 3) - v.begin();  // num:=(3未満の値の数).

エイリアス

using llong = long long;
using vi    = std::vector<int>;
using vvi   = std::vector<vi>;
using pii   = std::pair<int,int>;

エイリアス2とは,任意の型名に対し別の型名を定義するものです。 long long など利用頻度が多いものは,タイプしやすい短い型名にしています。

const変数

constexpr int       INF  = 1e9;
constexpr long long LINF = 1e18;
constexpr double    EPS  = 1e-10;
constexpr int       MOD  = 998'244'353;
constexpr int       MOD2 = 1e9+7;

競プロで利用頻度の多い数値は const変数として定義しています。 INF や EPS は,無限大や極小値を表すダミー値です。 また,MOD は AtCoder に頻出する素数です。

std::vectorの入出力演算子

template <typename Type>
std::istream &operator>>(std::istream &is, std::vector<Type> &v) {
    for(auto &in : v) is >> in;
    return is;
}

template <typename Type>
std::ostream &operator<<(std::ostream &os, const std::vector<Type> &v) {
    for(auto itr = v.cbegin(); itr != v.cend(); ++itr) os << (itr == v.cbegin() ? "" : " ") << *itr;
    return os;
}

配列の入出力を行う際,for文で記述しますが,タイプ量が多くて面倒です。 そのため,std::vector の入出力演算子を定義しています。

vector<int> v(n);
cin >> v;
...
cout << v << endl;

debugマクロ

#ifdef DEBUG

#include "debug.hpp"
using namespace algorithm;

#else

#define debug(...) static_cast<void>(0)

#endif

ifdef を用いて,ローカル環境のみで動作するデバッグマクロを定義しています。

ライブラリの中身はこちらのようになっています。詳しいデバッグマクロの説明は別記事に書こうと思います。

あとがき

あくまで競プロ用として。

【参考】他の方のテンプレート


  1. 一部世間では「575」と表現されるそうです。
  2. C++エイリアス宣言する方法は,typedef と using の2通りありますが,usingの方がモダンな方法として推奨されているようです(こちらの記事参照)。