C++で競プロを始めるにあたっての環境作り
どうも、るりんぐです。
最近AtCoerが盛り上がっていると巷で話題なので私も乗っかろうと思います。
して、やりたくなるのが環境構築。 競プロが快適に行えるような環境を作っていきます。
目次
現環境
これからやること
- 便利なマクロなどを追加
- 一部マクロをsyntaxの対象にする
- マクロなどを書いたソースをテンプレート化する
便利なマクロ
競プロはスピードが命。ということで、for文を簡略したり、型宣言を簡単にしたりします。 以下は僕が今使っているC++テンプレートです。
# include <bits/stdc++.h> # define rep(i, n) for(int i=0, i##_len=(n); i<i##_len; ++i) # define reps(i, n) for(int i=1, i##_len=(n); i<=i##_len; ++i) # define rrep(i, n) for(int i=((int)(n)-1); i>=0; --i) # define rreps(i, n) for(int i=((int)(n)); i>0; --i) # define ALL(x) (x).begin(), (x).end() # define SZ(x) ((int)(x).size()) # define pb push_back # define optimize_cin() cin.tie(0); ios::sync_with_stdio(false) using namespace std; using lint = long long; template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; } template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; } int main() { return 0; }
他にも検索すれば、便利なマクロが紹介されています。
#include <bits/stdc++.h>
vector
やstring
などの標準ライブラリを一括でインクルードしてくれます。
ただしg++依存みたいなのでbccなどじゃ使えないです。
rep(i, n)
rep
はrepeat
の略です。これを書くだけであのfor文の長ったらしい構文を書かなくて良くなります。
rep (i, 10) { printf("%d", i); }
また、多重forでありがちなミス
for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; i++) { } }
こんな感じで2つ目のforのインクリメントを間違えちゃう、みたいなことも起こらなくなります。
また、repの亜種みたいなのを定義していますが、カウントを1から始めたりi減少でforを回すときに使います。
マクロ名 | 意味 |
---|---|
rep | 0から変数増加でn-1までn回実行 |
reps | 1から変数増加でnまでn回実行 |
rrep | n-1から変数減少で0までn回実行 |
rreps | nから変数減少で1までn回実行 |
(ただ、iの宣言部がmainにないのは気持ち悪いですね。やむなし。)
ALL(v), pb
よくあるこれ
sort(v.begin(), v.end());
を簡潔に書けます。
sort(ALL(v));
また、push_backも頻出な割に打ちにくいのでpbで通るようにしました。
vec.push_back(10); vec.pb(10);
SZ(x)
x.size();
が簡潔に書けるようになるんですが、それ以上にx.size()
はunsigned型なので足し引きしたときに余計なエラーがでないようにキャストしている、という意味のほうが強いかもしれません。
optimize_cin()
cin
って実は低速なんですよね。だから普通はscanf()
を使って入力を受けつけるんですが、cinで書きたいときだってある。
そういうときは、このマクロを呼び出せばある程度ならcinを高速化できます。
ただ、ただ副作用でscanfとかの動作がバグるとかいう噂もあるので、main関数には書いていません。
using
using namespace std
はいいとして、using lint = long long
でlong long
を書くのを簡略化しています。問題設定的にlong longじゃないととけないものもあるので定義しておいて損はありません。
ちなみに略し方は宗派があるみたいで、ll
, lint
, int64
, lli
などがその例です。
僕個人としては、ll, lli
はなんか気持ち悪いし、int64
は見やすいですけどちょっと長いので、打ちやすくてそれっぽいlint
を採用しました。
chmax, chmin
よくある、
if (a > b + c)
{
a = b + c;
}
を関数化しました。これもよく使いますよね。
一部マクロをsyntaxへ追加
一部っていってもrep
とその仲間たちだけなんですけど、こいつらはforと同じように色がついたほうがいいかなということで。
> neovimの場合 cd /usr/share/nvim/runtime/syntax > vimの場合 cd /usr/share/vim/runtime/syntax vim cpp.vim
cpp.vimを開くとぶわーっとsyntaxの設定がされていますが、17行目を以下のように変更
syn keyword cppStatement new delete this friend using rep reps rrep rreps
これでrepもsyntaxの対象になりました。
テンプレート化
最後にこの競プロテンプレートをぱっとvimに書きだせるようにします。
# include <bits/stdc++.h> # define rep(i, n) for(int i=0, i##_len=(n); i<i##_len; ++i) # define reps(i, n) for(int i=1, i##_len=(n); i<=i##_len; ++i) # define rrep(i, n) for(int i=((int)(n)-1); i>=0; --i) # define rreps(i, n) for(int i=((int)(n)); i>0; --i) # define ALL(x) (x).begin(), (x).end() # define SZ(x) ((int)(x).size) # define pb push_back # define optimize_cin() cin.tie(0); ios::sync_with_stdio(false) using namespace std; using lint = long long; template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } ret$ template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } ret$ int main() { return 0; }
sonictemplate-vimの導入
このプラグインは、事前に書いておいたテンプレートファイルをコマンドを打つだけでばっとコピーしてくれます。スニペット機能もあるみたいですね。
私はプラグイン管理はdeinで行っておりますので、
call dein#add('mattn/sonictemplate-vim')
で追加しました。
テンプレートファイルの追加
まず、テンプレートファイルを置くディレクトリを作成します。どこでも良いはずなので、都合の良いところに作ってください。
僕は mkdir ~/.config/nvim/template
にしました。作ったら./template
に移動して、関連付けるファイルの名前のフォルダを作ります。今回はC++なので、
mkdir cpp
です。そして、cppに入り、
vim base-compe.cpp
でテンプレートファイルを作ります。ファイル名はなんでもいいですが、接頭のbase-
は必須なので注意してください。
作ったら先程のテンプレートファイルをコピペして保存して終了してください。
さあ、あとはこれで、cppファイルをvimを立ち上げて、
:Template compe
とコマンドを叩けば、めでたく先程のテンプレートファイルが書き込まれます。
まとめ
プラグインって素晴らしい。
もう少しマクロ増やしたり、あとAtCoderとかだと、問題を自動で取ってきて自動でサンプルケース試すみたいなこともできるみたいなんでそういうのもできればいいですね。