んぐのルーズリーフ

んぐの日記。最近はScrapBoxが主

C++で競プロを始めるにあたっての環境作り

どうも、るりんぐです。

最近AtCoerが盛り上がっていると巷で話題なので私も乗っかろうと思います。


して、やりたくなるのが環境構築。 競プロが快適に行えるような環境を作っていきます。


目次




現環境

  • WSL(Ubuntu) これが出てWindows環境での開発ハードルがぐっと下がりましたよね
  • エディタ:neovim 基本的な設定は完了済み
  • 言語:C++



これからやること

  • 便利なマクロなどを追加
  • 一部マクロを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>

vectorstringなどの標準ライブラリを一括でインクルードしてくれます。


ただしg++依存みたいなのでbccなどじゃ使えないです。



rep(i, n)

reprepeatの略です。これを書くだけであの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 longlong 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の対象になりました。

f:id:luling:20181201163047p:plain





テンプレート化

最後にこの競プロテンプレートをぱっと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の導入

github.com

このプラグインは、事前に書いておいたテンプレートファイルをコマンドを打つだけでばっとコピーしてくれます。スニペット機能もあるみたいですね。

私はプラグイン管理は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とかだと、問題を自動で取ってきて自動でサンプルケース試すみたいなこともできるみたいなんでそういうのもできればいいですね。