競技プログラミングで個人的に使っているマクロ
私が普段競技プログラミングで使っているマクロについて簡単にまとめておこうと思ったのでこれを書きました。
完全に自作ではなく、他の人を参考にしたものもあります。
- #include <bits/stdc++.h>
- using namespace std;
- ソースコードの置換
- 型名に新しい名前を付ける
- templateによるマクロ
- 複数変数の標準入力の省略
- 汎用の定数について
- 汎用の自作関数について
- まとめ
#include <bits/stdc++.h>
ライブラリをいっぱいincludeしてくれます。
#include <bits/stdc++.h>
using namespace std;
標準ライブラリのstd
の名前空間にあるもののstd::
を省略できます。
using namespace std;
ソースコードの置換
以下のように書くとA
をB
に置換します。
#define A B
私は次のようなものを使っています。
// for文の省略 #define rep(i, n) for(long long i = 0; i < (n); i++) #define REP(i, s, n) for(long long i = (s); i <= (n); i++) #define repr(i, n) for(long long i = (n - 1); i >= 0; i--) #define REPR(i, s, n) for(long long i = (s); i >= (n); i--) // イテレータ指定の省略 #define all(a) (a).begin(), (a).end() #define rall(a) (a).rbegin(), (a).rend() // 配列の総和 #define sumvec(v) accumulate(all(v), 0LL) // 実数の表示桁数指定 #define DOUBLE fixed << setprecision(15) // デバッグ用の表記 #define OK cerr << "OK\n" #define OK1 cerr << "OK1\n" #define OK2 cerr << "OK2\n" #define dbg(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << __FILE__ << endl; // size()のint型へのキャスト #define sz(s) (int)s.size()
型名に新しい名前を付ける
以下のように書くとデータ型に新しい名前を付けることが出来ます。
この例ではA
という型がB
という名前でも使えるようになります。
typedef A B;
これを使って私は以下のようにデータ型の名前を省略しています。
typedef long long ll; typedef long double ld; typedef vector<int> vi; typedef vector<long long> vll; typedef vector<double> vd; typedef vector<ld> vld; typedef vector<char> vc; typedef vector<bool> vb; typedef vector<string> vs; typedef vector<vi> vvi; typedef vector<vll> vvll; typedef vector<vd> vvd; typedef vector<vld> vvld; typedef vector<vc> vvc; typedef vector<vb> vvb; typedef pair<ll,ll> P; typedef vector<P> vP;
templateによるマクロ
templateについて1から説明しているときりがないので省略します。
任意のデータ型について対応した等しい処理を行えるものだという認識で大丈夫です。
複数変数のデバッグ
void debug() { cerr << "\n"; } template<class T, class... Args> void debug(const T &x, const Args &... args) { cerr << x << " "; debug(args...); }
これを使うと複数の変数のデバッグを簡単に書けます。
int a = 5; int b = 10; debug(a, b); // 5 10 と表示して改行されます。
標準ライブラリの関数への機能の追加
ライブラリ内で定義されているmin()
, max()
は通常は二値比較ですが、vector
などのmin(max)_element
を用いる場合にもmin()
, max()
で求めることが出来るようになります。
template<class T> auto min(const T& a) { return *min_element(a.begin(), a.end()); } template<class T> auto max(const T& a) { return *max_element(a.begin(), a.end()); }
vector<int> a = {1, 2, 3, 4, 5}; cout << max(a) << endl; // 5 と表示される
最大値、最小値の更新用の関数
最大値、最小値を更新した際などに第一引数を第二引数で更新し、trueを返します。
template<class T> inline bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; } template<class T> inline bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
これを使うと、以下の2つがほとんど同じような動作をします。
ans = max(ans, tmp);
chmax(ans, tmp);
更新したらtrueを返すようになっているので、次のようにも書くことが出来ます。
if(chmax(ans, tmp)) { // ansが更新された時にする処理 }
標準入出力への利用
簡単に言うと<<
や>>
といった演算子で出来る事を増やします。
例えば、以下のようなもの。
vectorに<<
演算子を使うと中身を順番に表示するようになっています。
template<class T> ostream& operator<< (ostream& ost, const vector<T>&v) { os << "{"; for (int i = 0; i < (int)v.size(); i++) { if(i) ost << " "; ost << v[i]; } ost << "} \n"; return ost; }
これにより、次のように書くことが出来ます。
vector<int> a = {1, 2, 3, 4, 5}; cout << a; // {1 2 3 4 5} と表示されます。
これと同様なものを多く用意しています。
// pair型のfirst, secondを同時に出力する template<class A, class B> ostream& operator<< (ostream& ost, const pair<A, B> &p) { ost << "{" << p.first << ", " << p.second << "} "; return ost; } // dequeの要素を順番に出力する template <typename T> ostream& operator<<(ostream& os, const deque<T> &vec) { os << "deq["; for (auto v : vec) { os << v << ","; } os << "]\n"; return os; } // mapの要素を順番に表示する template<class A, class B> ostream& operator<< (ostream& ost, const map<A, B>&v) { ost << "{"; for (auto p : v) { ost << "{" << p.first << ", " << p.second << "} "; } ost << "}\n"; return ost; } // setの要素を順番に出力するようにする template<typename T> ostream& operator<< (ostream &os, const set<T> &vec) { os << "{"; for (auto v : vec) { os << v << ","; } os << "}\n"; return os; } // multisetの要素を順番に出力するようにする template<typename T> ostream& operator<<(ostream &os, const multiset<T> &vec) { os << "{"; for (auto v : vec) { os << v << ","; } os << "}\n"; return os; } // vectorへの標準入力を順番に実行する template<typename T> istream& operator>> (istream& is, vector<T>& vec) { for(T& e : vec) { is >> e; } return is; } // pair型のfirst, secondへの標準入力を同時に行うようにする template<typename A, typename B> istream& operator>> (istream& is, pair<A, B>& p) { is >> p.first >> p.second; return is; } // pair型の + 演算子はfirst, second同士を足し合わせるようにする template<typename A, typename B> pair<A, B> operator+ (const pair<A, B> &l, const pair<A, B> &r) { return make_pair(l.first + r.first, l.second + r.second); } // pair型の - 演算子はfirst, second同士を引くようにする template<typename A, typename B> pair<A, B> operator- (const pair<A, B> &l, const pair<A, B> &r) { return make_pair(l.first - r.first, l.second - r.second); }
複数変数の標準入力の省略
今まで書いてきたことを用いて、以下のようなことも出来ます。
#define INT(...) int __VA_ARGS__; IN(__VA_ARGS__) void scan(int& a) { cin >> a; } void IN() {} template<class Head, class... Tail> void IN(Head& head, Tail&... tail) { scan(head); IN(tail...); }
これは何かというと、INT()の引数にカンマ区切りで書いた引数を宣言、標準入力を行うというものです。
これを用いると、以下の2つが同じ意味になります。
int a, b, c;
cin >> a >> b >> c;
INT(a, b, c);
汎用の定数について
よく使う定数などはあらかじめ宣言しておきます。
// グリッドの4近辺を探索する時の、座標の差分用の配列 const int dy[] = {-1, 0, 0, 1}; const int dx[] = {0, -1, 1, 0}; // グリッドの8近辺を探索する時の、座標の差分用の配列 const int dy8[] = {-1, -1, -1, 0, 0, 1, 1, 1}; const int dx8[] = {-1, 0, 1, -1, 1, -1, 0, 1}; // infinityを表す大きな値 const int inf = 1001001001; const long long INF = ((1LL << 62) - (1LL << 31)); // 円周率π const long double pi = acos(-1.0); // 頻出のMOD const long long mod = 1000000007; const long long MOD = 998244353;
汎用の自作関数について
定数と同様に、よく使う関数はあらかじめ定義してあります。
// 繰り返し自乗法で a ^ b % mod を返す long long powmod(long long a, long long b) { long long c = 1; while(b > 0) { if(b & 1) { c = a * c % mod; } a = a * a % mod; b >>= 1; } return c; } // nCr % mod を返します long long nCrmod(long long n, long long r) { long long x = 1, y = 1; for(long long i = 0; i < r; i++) { x = x * (n - i) % mod; y = y * (i + 1) % mod; } return x * powmod(y, mod - 2) % mod; } // 約数を列挙してvectorで返します vector<long long> divisor(long long x) { vector<long long> v; for(long long i = 1; i * i <= x; i++) { if(x % i == 0){ v.push_back(i); if(i * i != x) v.push_back(x / i); } } sort(v.begin(), v.end()); return v; }; // 素因巣分解をして<key, value>を<素因数, 素因数の個数>としてmapで返します map<long long, long long> prime_factor(long long n) { map<long long, long long> m; for(long long i = 2; i * i <= n; i++) { while(n % i == 0) { m[i]++; n /= i; } } if(n != 1) m[n] = 1; return m; }
まとめ
紹介したものをまとめると以下のようになります。
コードの行が増えすぎないように改行してない部分がありますがご了承ください。
あくまで私個人の例なので、使用は自己責任でお願いします。
#include<bits/stdc++.h> using namespace std; #define rep(i,n) for(long long i = 0; i < (n); i++) #define REP(i,s,n) for(long long i = (s); i <= (n); i++) #define repr(i,n) for(long long i = (n - 1); i >= 0; i--) #define REPR(i,s,n) for(long long i = (s); i >= (n); i--) #define all(a) (a).begin(), (a).end() #define rall(a) (a).rbegin(), (a).rend() #define sumvec(v) accumulate(all(v), 0LL) #define DOUBLE fixed << setprecision(15) #define OK cerr << "OK\n" #define OK1 cerr << "OK1\n" #define OK2 cerr << "OK2\n" #define sz(s) (int)s.size() #define dbg(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << __FILE__ << endl; typedef long long ll; typedef long double ld; typedef vector<int> vi; typedef vector<long long> vll; typedef vector<double> vd; typedef vector<ld> vld; typedef vector<char> vc; typedef vector<bool> vb; typedef vector<string> vs; typedef vector<vi> vvi; typedef vector<vll> vvll; typedef vector<vd> vvd; typedef vector<vld> vvld; typedef vector<vc> vvc; typedef vector<vb> vvb; typedef pair<ll,ll> P; typedef vector<P> vP; void debug() { cerr << "\n"; } template<class T, class... Args> void debug(const T &x, const Args &... args) {cerr << x << " "; debug(args...);} template<class A, class B> ostream& operator<< (ostream& ost, const pair<A, B> &p) { ost << "{" << p.first << ", " << p.second << "} "; return ost; } template<class T> ostream& operator<< (ostream& ost, const vector<T>&v) { ost << "{"; for (int i = 0; i < (int)v.size(); i++) { if(i) ost << " "; ost << v[i]; } ost << "} \n"; return ost; } template <typename T> ostream& operator<<(ostream& os, const deque<T> &vec) { os << "deq["; for (auto v : vec) os << v << ","; os << "]\n"; return os; } template<class A, class B> ostream& operator<< (ostream& ost, const map<A, B>&v) { ost << "{"; for (auto p : v) { ost << "{" << p.first << ", " << p.second << "} "; } ost << "}\n"; return ost; } template<typename T> istream& operator>> (istream& is, vector<T>& vec) { for(T& e : vec) is >> e; return is; } template<typename A, typename B> istream& operator>> (istream& is, pair<A, B>& p) { is >> p.first >> p.second; return is; } template<typename A, typename B> pair<A, B> operator+ (const pair<A, B> &l, const pair<A, B> &r) { return make_pair(l.first + r.first, l.second + r.second); } template<typename A, typename B> pair<A, B> operator- (const pair<A, B> &l, const pair<A, B> &r) { return make_pair(l.first - r.first, l.second - r.second); } template<typename T> ostream& operator<< (ostream &os, const set<T> &vec) { os << "{"; for (auto v : vec) os << v << ","; os << "}\n"; return os; } template<typename T> ostream& operator<<(ostream &os, const multiset<T> &vec) { os << "{"; for (auto v : vec) os << v << ","; os << "}\n"; return os; } template<class T> auto min(const T& a){ return *min_element(a.begin(), a.end()); } template<class T> auto max(const T& a){ return *max_element(a.begin(), a.end()); } template<class T> inline bool chmax(T& a, T b){ if(a < b){ a = b; return true; } return false; } template<class T> inline bool chmin(T& a, T b){ if(a > b){ a = b; return true; } return false; } #define INT(...) int __VA_ARGS__; IN(__VA_ARGS__) #define LL(...) long long __VA_ARGS__; IN(__VA_ARGS__) #define CHR(...) char __VA_ARGS__; IN(__VA_ARGS__) #define DBL(...) double __VA_ARGS__; IN(__VA_ARGS__) #define STR(...) string __VA_ARGS__; IN(__VA_ARGS__) #define LD(...) long double __VA_ARGS__; IN(__VA_ARGS__) void scan(int& a){ cin >> a; } void scan(long long& a){ cin >> a; } void scan(char& a){ cin >> a; } void scan(double& a){ cin >> a; } void scan(string& a){ cin >> a; } void scan(long double& a){ cin >> a; } void IN(){} template<class Head, class... Tail> void IN(Head& head, Tail&... tail){ scan(head); IN(tail...); } const int dy[] = {-1, 0, 0, 1}; const int dx[] = {0, -1, 1, 0}; const int dy8[] = {-1, -1, -1, 0, 0, 1, 1, 1}; const int dx8[] = {-1, 0, 1, -1, 1, -1, 0, 1}; const int inf = 1001001001; const long long INF = ((1LL << 62) - (1LL << 31)); const long double pi = acos(-1.0); const long long mod = 1000000007; const long long MOD = 998244353; ll powmod(ll a, ll b){ ll c = 1; while(b > 0){ if(b & 1){ c = a * c % mod; } a = a * a % mod; b >>= 1; } return c; } ll nCrmod(ll n, ll r){ ll x = 1, y = 1; for(ll i = 0; i < r; i++) { x = x * (n - i) % mod; y = y * (i + 1) % mod; } return x * powmod(y, mod - 2) % mod; } vll divisor(ll x){ vll v; for(ll i = 1; i * i <= x; i++) if(x % i == 0){ v.push_back(i); if(i * i != x) v.push_back(x / i); } sort(v.begin(), v.end()); return v; }; map<ll, ll> prime_factor(ll n){ map<ll, ll> m; for(ll i = 2; i * i <= n; i++){ while(n % i == 0){ m[i]++; n /= i; } } if(n != 1) m[n] = 1; return m; } int main() { return 0; }
間違い等ありましたら連絡いただけますと幸いです。
拙い説明ではありましたが、お付き合いいただきありがとうございました。