13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自分が競プロで使っているテンプレートの解説

Last updated at Posted at 2023-03-08

はじめに

タイトル通り、自分が 競技プログラミングにおいて 素早くコーディングするために使っているテンプレートやマクロを紹介する記事です。競プロ以外では好ましくないことをたくさんしていると思いますが、そこは許してください。

テンプレート等の独自な定義をする機能を使うと読みづらくなる、というのはもっともですが、速解きには非常に便利なうえ、逆に使ったほうがコードの見通しがよくなるパターンもあるので、自分は積極的に使う派です。

また、ここで紹介する大体のものはどこかしらで見覚えがあるものだと思います。強い人の真似をするのも、強くなるためのひとつの方法だと思うので…

(問題なのは、どこから真似したか忘れたものが大半なため、出典元の紹介ができないことです。勝手に持ち出して我が物顔で紹介するような形になってしまい申し訳ないです…
自作のものは「自作です!」と明記しますが、それがないものはどこかから真似したんだなーと思ってください。)

2023/08/03,追記: テンプレートの変更に伴い、当記事の内容も一部更新しました。
2023/09/17 追記: 同上(その他(関数など)の項のprint_vecに大幅更新あり)

本題

include関連

#include <bits/stdc++.h>
using namespace std;
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif

上2行に関してはこれ(APG4b)を読むと良いです。
ついでに、bits/stdc++.hはプリコンパイルしておくとコンパイルが速くなって快適です。こちらの記事が参考になりました。 (2024/03/09 追記)

下4行は AtCoder Library を使うためのものです。本来#if#endifの行は不要なのですが、ジャッジサーバーにAtCoder Libraryが導入されていないところで「<atcoder/all>をincludeして!」と言うとエラーが発生するので、事前に導入された環境かチェックしてからincludeしています。AOJやアルゴ式での不用意なエラーが避けられるので便利ですね。

プリコンパイルとかAtCoder Libraryの導入といった環境構築については、こちらの記事もぜひどうぞ。 (ダイマ)

2024/03/09 追記
#include <atcoder/all>はコンパイル速度に結構影響しているようなので、とりあえず毎回書いておくより使いたいものだけ適宜includeするほうがいいかもしれません。
ここはお好みでどうぞ。 (私は爆速でコンパイルできるほうが嬉しいので、適宜includeしています)

struct Init { Init() { ios::sync_with_stdio(0); cin.tie(0); } }init;

Initの方は、入出力を高速化させるおまじないです。競プロではあまり必要ない機能を無効にして高速化しようというものです1
std::cinscanf()printf()std::coutを併用する人でなければ付けておくと得です。
詳しい説明が欲しい人はios::sync_with_stdio(0)で検索してください(丸投げ)。


2023/08/03 追記

#if !__INCLDE_LEVEL__
#include __FILE__

// 任意のテンプレ
int main(){
    // 任意の処理
}

#else
#include <bits/stdc++.h>
// 以下、汎用テンプレ

#endif

本来(基本的に)C++では関数やテンプレートの定義を上で済ましてからmain関数を書く…という形をとる必要があるのですが、それではテンプレートが膨大になってくると提出コードの可読性が損なわれてしまいます。
そこで、main関数のような主要な部分を上に切り出すための記法がこちらとなっている…らしいです。

割と裏技なようで、環境によってはシンタックスハイライトがおかしくなるなどの副作用があったりなかったりするようですので、これの使用は(当記事内でも特に)自己責任の範疇だと思います。あとAtCoderでは問題なく動作しますが、ほかのジャッジサイト(例:AOJ)では動作しない場合があります。
この記法に関してはこちらの記事を参考にしました。詳細を知りたい方はぜひ。

追記終了


マクロ関連

using ll = long long;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;

#define rep(i, x, limit) for (int i = (int)x; i < (int)limit; i++)
#define REP(i, x, limit) for (int i = (int)x; i <= (int)limit; i++)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define el '\n'
#define spa " "
#define Yes cout << "Yes" << el
#define No cout << "No" << el
#define YES cout << "YES" << el
#define NO cout << "NO" << el
#define eps (1e-10)
#define Equals(a,b) (fabs((a) - (b)) < eps )
#define debug(x) cerr << #x << " = " << x << el

いろいろと並んでいて見るのが面倒かもしれませんが、コード中で多用するのはこのマクロ関連なので一番本質的なところだと思います。

まずllは、C++における64bit整数型であるlong longを宣言するのが面倒なので省略しています。2
というかこれに限らず、マクロは全部「毎回書くのは面倒なので省略しよう」という考えに基づいています。(それを踏まえると、この項の大部分が説明するまでもなくなってきます)

repはfor文の省略です。llrepはかなり一般的なやつですね。repの定義は人それぞれだったりしますが、自分は{カウンタ変数名, 初期化値, 終了条件値}となるよう引数を3つとらせています。
逆for文(カウンタ変数をデクリメントするやつ)をrrepと省略していた頃もありましたが、使いどころがそこまでないのと微妙に扱いづらかったので消しました。

REPのほうはといいますと、repの終了条件が <(大なり) であったところを <=(大なりイコール) に変えただけのものです。repは半開区間、REPは閉区間といえます。
repの終了条件値に+1すればいいじゃん」と言われるとそれはそうなのですが、理解するとこれが意外と便利です。読み手側の困惑を招きやすいと思いますが…

allも割と使ってる人がいるマクロだと思います。イテレータを引数にとるSTL、例えばstd::sortなどで便利ですね。rallは逆イテレータを返します。std::sortで逆順ソートさせる以外の使い方をした記憶がないですが、あると便利です。

elは改行コードの省略です。'\n'って出力するたびに打つの結構面倒ですよね?
std::endlでも改行できますが、出力バッファを毎回フラッシュするので高速な出力ではないそうです。たくさん出力する問題だとかなり実行時間に影響するので、'\n'のほうがよいです。ただインタラクティブ問題ではフラッシュする必要があるので、endlをそのまま置き換えはしていません。
(\n/nと誤記していました。2023/03/09 訂正
@gengar-094 様にご指摘いただきました、ありがとうございます)

spaは自作で、これに類似したマクロを使っている人は見たことないです。まぁ見たまんま、半角スペースの省略です。"space"の3文字をとって命名しています。さっきのelといい文字列関連は入力するのが面倒なので重宝しています。

YesNoはよく出力として求められがちな"Yes"と"No"の出力を略しています。bool型のYESNO関数として使ってる人が多い気がしますが、個人的には出力に絞った方が柔軟な気がします。


2023/08/03 追記

上記のやつは元々YESNOに割り振っていたのですが、最近YesNoYESNOで分けてみました。このほうが文字に直接対応していてわかりやすく、また昔の問題では"YES","NO"の文字列を出力するよう求められることが多かったためです。実際こっちのほうが便利。
あとtypedefを用いてllなどを定義していたのですが、どうやらusingを用いて定義する記法の方が最新版C++(?)に即した書き方らしいです。ということでusingを使用するよう変更しました。

追記終了


ここから下二つのepsEqualsは、かの螺旋本から取ってきたものです。まだ使ったことはないですが、どちらも小数点型関係のものです。
epsは非常に小さな小数点型の数値です。これがあると誤差に対して強くなるとかなんとか…(よくわかっていない)
Equalsは、小数点型特有の誤差を考慮し、引数の2値が厳密に一致していなくともeps未満の差であれば一致していると返す関数のようです。
(2023/04/05 追記)

debug()は引数の変数名とその値を一行で(標準エラー出力へ)出力します。
(2024/03/09 追記)

定数関連

const double pi = 3.141592653589793238;
const int inf = 1073741823;
const ll infl = 1LL << 60;
const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string abc = "abcdefghijklmnopqrstuvwxyz";

piは円周率です。(幾何問題から逃げているので、使った記憶が一度くらいしかありませんが…)
infはint型の大きい数です。$10^9$より大きく、inf+infしてもオーバーフローしない数です。
inflはlong long型の大きい数です。具体的な大きさは$2^{60} = 1,152,921,504,606,846,976$です。(符号付きであれば)63bit使えるうちの60bit使っているので、十分大きいと思います。少なくとも自分はこの大きさで困ったことがないです。


2023/08/03 追記

piはC++20から使用可能になる、numbersヘッダに含まれているらしいです。つまり、(追記時点では)もうすぐAtCoderにおいてC++20, 23が解禁されたため不要なテンプレートになりそうです。

2023/09/17 追記:
AtCoderでC++20以降のバージョンが使用可能になったため、AtCoder上ではpiは不要になったといえます。しかし、AtCoder以外のジャッジシステムがC++20以降を採用しているとは限らないため、まだ置いています。
追記終了

ABC,abcはアルファベット26文字を昇順に並べた文字列です。まれにABC-A問題あたりで求められたので、一応入れてみました。現時点では使ったことがないです。

追記終了


その他(関数など)

ここからは大体コメントが付属しています。なので、提出コードだけでも読み解ける情報な気がします。


2024/03/09 追記

template<typename T1, typename T2>
std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){
    os << "{" << p.first << "," << p.second << "}";
    return os;
}

std::pairstd::coutに直接渡せるよう演算子を定義しています。
std::cout << p.first << spa << p.second << el;と書いてデバッグする場面が多かったので、割と重宝しています。


template<typename T1, typename T2> inline bool chmax(T1 &a, T2 b) {
    bool compare = a < b;
    if(compare) a = b;
    return compare;
}
template<typename T1, typename T2> inline bool chmin(T1 &a, T2 b) {
    bool compare = a > b;
    if(compare) a = b;
    return compare;
}

2つの引数を比較して、1つ目の値が2つ目の値より大きい(or小さい)なら更新しつつtrueを返す関数です。これも割と一般的なやつです。
TwoSquirrelsさん(X,旧Twitter)に教えていただいた書き方を採用しています。(2024/03/09 追記)
特に動的計画法でよく使う気がします。結構便利なので持っておいて損はないです。


// 4近傍、(一般的に)上右下左
const int dy[4] = {-1,0,1,0};
const int dx[4] = {0,1,0,-1};

// 8方向 左上, 上, 右上, 右, 右下, 下, 左下, 左
const int dy[8] = {-1,-1,-1,0,1,1,1,0};
const int dx[8] = {-1,0,1,1,1,0,-1,-1};

auto outof = [&](uint y, uint x){
    return y>=h or x>=w;
};

幅優先探索をするときに非常に便利です。これがなければ幅優先探索が好きになるどころか嫌いになっていると思います。
斜め方向を加えた8近傍バージョンもありますが、あまり使いません。

outofは範囲外アクセスを防ぐためのラムダ式関数です。h,wが共にnの場合とかもあるので、適宜書き換えてください。
符号無し整数にすることで条件を減らせるテクがあります。

print_vec (std::vectorの出力)

// 配列の要素を空白区切りで出力 第二引数をtrueにすると改行区切り
template<typename T> inline void print_vec(const vector<T> &v, bool split_line=false) {
    if(v.empty()){
        cout << "This vector is empty." << el;
        return;
    }
    constexpr bool isValue = is_integral<T>::value;
    for (int i = 0; i < (int)v.size(); i++) {
        if constexpr(isValue){
            if((v[i]==inf) || (v[i]==infl)) cout << 'x' << " \n"[split_line || i+1==(int)v.size()];
            else cout << v[i] << " \n"[split_line || i+1==(int)v.size()];
        }else cout << v[i] << " \n"[split_line || i+1==(int)v.size()];
    }
}

自作です。基本的にはデバッグで使用しますが、たまにこの通りのフォーマットで出力を求められる場面もあります。
infinflを含む配列を出力したい場合もしばしばありますが、非常に大きい値が出力されると見づらいので置き換えています。
空の配列を出力したときにわかりづらくなるのを防ぐための処理もあります…が、そんなに役に立った記憶はないです。

2023/09/17 追記:
以前まで、要素 という風に、各要素+半角スペースの形式で出力していました。そしてループ終了後に改行を一つ、という動作をさせていたのですが…
これだと末尾の要素を出力する際に要素(空白)(改行)という風に、余計な空白が出力されてしまいます。
AtCoderのジャッジ上では問題ないですが、余計な空白を出力していると不正解であるとみなされるジャッジも結構存在します(例えばPaizaが該当したはず)。そういったジャッジにも対応できる、丁寧な出力形式に変更しました。

また、問題によっては配列内の各要素を、空白区切りではなく改行区切りで出力したくなります。これにも対応させるため、第二引数split_lineを追加しました。(以下ではvをvector<T>とします)
print_vec(v,true)とすると改行区切りになり、print_vec(v)とすると空白区切りになります。第二引数は省略するとfalseで初期化されるので、従来の使い勝手そのままです。

" \n"[split_line || i+1==(int)v.size()] が何を言ってるかわからない人向け

少し奇怪な記法になっていますが、分解して見ていきましょう。
まずやっていることの本質として、"文字列"[idx]で文字列のidx番目の要素(文字)にアクセスしています。
これ自体は普通のことですね。string型の変数に格納せず、生の文字列に直接アクセスしているのが少し見慣れないかもしれませんが、たまに実装の簡略化で使えるので覚えておくとよいと思います。

ここでは、" \n"という文字列にアクセスしています。一見3文字ありますが、'\n'はエスケープシーケンスという特殊なやつで、これはまとめて1文字分として扱われます(なのでchar型として扱えます)。そして、'\n'が出力されるわけではなく、改行という意味に解釈されます。(これ、elの項に書くべきだったかも…)
ということで、" \n"(' ')('改行')という風な二文字の文字列として解釈されます。0番目の要素にアクセスしたら半角スペースが、1番目にアクセスしたら改行を取り出すことができます。

あとは[]内についてです。これはifなどで用いる表記のそれと同じで、bool変数のsplit_lineとbool値のi+1==(int)(v.size())についてOR演算を適用しています。前者は関数呼び出しの際の第二引数に対応しており、後者は現在アクセスしている要素が渡した配列における末尾の要素か?という式に対応しています。
これら2要素のうち1つ以上trueならばtrue = 1が、そうでなければfalse = 0[idx]のidxとして与えられることになります。
つまりどちらかもしくは両方のbool値がtrueならば、[1]で1番目の要素にアクセスすることになります。そうでなければ[0]で0番目の要素にアクセスすることになります。
合わせると、bool値のどちらか1つ以上がtrueなら改行を、どちらもfalseなら空白にアクセスすることになります。
ちなみに" \n"[i+1==(int)v.size()]は一つの典型というか、実装上のテクニックとして時々用いられることがあります。

追記終了

2024/07/06 追記
Tが数値型でないときにv[i]==inf || v[i]==inflをするとコンパイラに怒られるので回避していた…
つもりだったのですが、できていなかったので更新しました。
constexprをつけてコンパイル時に検査させると想定通りに動作するみたいです。
追記終了

2024/03/09 追記

template<typename T1, typename T2> inline void print_vec(const vector<pair<T1,T2>> &v, bool split_line=false){
    if(v.empty()){
        cout << "This vector is empty." << el;
        return;
    }
    for(int i = 0; i < (int)v.size(); i++){
        cout << '{';
        auto [a,b] = v[i];
        constexpr pair<bool,bool> isValue = {is_integral<T1>::value, is_integral<T2>::value};
        if constexpr(isValue.first){
            if(a==inf || a==infl) cout << "x,";
            else cout << a << ",";
        }else cout << a << ",";
        if constexpr(isValue.second){
            if(b==inf || b==infl) cout << "x,";
            else cout << b;
        }else cout << b;
        cout << "}" << " \n"[split_line || i+1==(int)v.size()];
    }
}

std::vector<std::pair<T1,T2>>に対して使えるprint_vecもあります。随分複雑な見た目になったのですが、やってることとしては本当にただの移植版です。
せっかくならstd::pairstd::coutに直接渡せるのを利用したかったのですが、各要素がinfinflに一致するか調べる機能を付けた都合上こうせざるを得ませんでした。無念…

追記終了

Timer (時間計測用class)

2024/03/09 追記

// std::chronoを利用した時間計測用クラス
class Timer{
    chrono::system_clock::time_point start;
    public:
        Timer() : start(chrono::system_clock::now()) {}
    
        double count(){
            chrono::duration<double> Time_ = chrono::system_clock::now() - start;
            return Time_.count();
        }

        bool is_under(double x){
            return (this -> count()) < x;
        }
};

自作です。
std::chronoを利用するとプログラムの実行時間を計測でき、ヒューリスティックコンテストや嘘解法をゴリ押しで通す(!?)ときに便利です。ただ微妙に用法が面倒なので、classにして使いやすくしました。
プログラム中の計測開始したいところでTimer timerという風に宣言すると、コンストラクタが呼び出されて計測を開始します。(大抵はmain関数のはじめに書くはず)
Timer.count()は計測開始から現在までの時間をdouble型で返します。
Timer.is_under(x)は「計測開始から現在までの時間がx未満か」を示すbool値を返します。

使用例
int main(){
    Timer timer;
    int n;
    cin >> n;
    while(n--) cout << n << el;
    
    // プログラム全体の処理時間を得られる
    cout << timer.count() << el;
}
int main(){
    Timer timer;
    int ans = 0;
    /*任意の処理*/

    // プログラム実行開始から1.95秒経過するまでwhileループを継続
    while(timer.is_under(1.95)){
        /*任意の処理*/
    }
    cout << ans << el;
}

特にwhileの条件として「x秒経過するまで」としたいときが多いですが、このclassを利用しない場合だと

auto Start = chrono::system_clock::now();
while(true){
    chrono::duration<double> Time = chrono::system_clock::now() - Start;
    if(Time.count() >= 秒数)  break;
}

と書く必要があったので、while(timer.is_under(秒数))と1行で書けるのは便利だと思います。

Random_Gen (乱数生成class)

2024/08/26 追記

// std::uniform_int_distributionを利用した一様乱数生成クラス
class Random_Gen{
    random_device seed_gen;
    mt19937 engine;
    uniform_int_distribution<int64_t> dist;
    public:
        // Constructor [l,r]で生成する値の範囲を指定
        Random_Gen() : engine(seed_gen()) {}
        Random_Gen(int64_t l, int64_t r) : engine(seed_gen()), dist(l,r) {}
        
        // 現在の生成する値の範囲をstd::pairで返す
        pair<int64_t,int64_t> get_range(){
            return make_pair(dist.min(),dist.max());
        }
        // 生成する値の範囲を[l,r]に変更する
        void set_range(int64_t l, int64_t r){
            uniform_int_distribution<int64_t>::param_type Param(l,r);
            dist.param(Param);
        }
        // [l,r]内の一様分布の整数を返す
        int64_t gen(){
            return dist(engine);
        }
        int64_t operator()(){ return gen(); }
};

自作です。
C++で乱数を使うの、割と面倒な気がするので整備しました。

一番楽に利用できるstd::rand()乱数の質が低いことで知られているうえC++14から非推奨になっていますから、避けたいです。
擬似乱数生成の手段としてはXORshiftとかMersenne Twister (std::mt19937) あたりが主流なようで、このclassでもstd::mt19937を利用しています。

得られた疑似乱数に対して剰余演算を用いて任意の範囲に丸める(?)と偏りが生じてしまうので、std::uniform_int_distributionを用いて一様分布乱数を得るべきです。
まぁこの辺りの説明は別の方の記事に任せるとして3、ざっくり言えばstd::random_device,std::mt19937,std::uniform_int_distributionといった先人の知恵に乗っかれば楽に良い疑似乱数を利用できるわけです。

しかしこの3行さえ書くのが面倒というわけで、そこでRandom_Genが生まれました。
使い方に関してはコメントに示した通りなので特筆することはないです。
std::uniform_int_distributionと違って、生成する値の範囲を半開区間[l,r)で指定する点にだけ注意してください。
何回か実際に使ったうえで、全開区間[l,r]のほうが使いやすそうなので変更しました。

.gen()だけでなく()だけでも乱数生成できるようにしました。Random_Gen Genがあるとして、Gen.gen()でもGen()でもOKという感じです。これ要る? という気もしますが、一応…

範囲を指定せずに呼び出した場合、[0,INT64_MAX(9'223'372'036'854'775'807)]の値が生成されるようになります。(std::uniform_int_distributionの仕様のため。)

使用例
int main(){
    // 1から6までの範囲の一様分布乱数を生成
    Random_Gen Random(1,6);
    /* 以下でも等価
    Random_Gen Random;
    Random.set_range(1,6);
    */
    auto [l,r] = Random.get_range();
    cout << l << " " << r << '\n';
    int n;
    cin >> n;
    for(int i=0;i<n;i++){
        cout << Random.gen() << " \n"[i+1==n];
        // Random.gen() は Random() と等価
    }
}

入力例:

10

出力例1:

1 6
1 6 3 4 5 4 1 3 4 2

出力例2:

1 6
1 6 6 6 3 5 2 5 1 4

おわり

本当はたまに使うテンプレートがまだありますが(エラトステネスの篩など)、大体そういったテンプレートにはコメントがついているので、その時は適宜読んでください。というかそういったテンプレートは大抵けんちょんさん(@drken)の記事から拝借したものなので、けんちょんさんの記事群を探せば詳細な定義が見つかると思います。
またテンプレートに追加があれば(、かつ覚えていれば)記事もあわせて更新すると思います。

おまけ(テンプレの全体像)

2023/08/03 追記
自分では気づいていなかったのですが、全体像があるほうが見やすいというレビューを頂いたので載せておきます。(ご意見ありがとうございます)

以下が2024/03/09時点で最新版のテンプレート全体像です。

#if !__INCLUDE_LEVEL__
#include __FILE__

int main(){
    
}

#else
#include <bits/stdc++.h>
using namespace std;
struct Init { Init() { ios::sync_with_stdio(0); cin.tie(0); cout << setprecision(13); } }init;

using ll = long long;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;

#define rep(i, x, limit) for (ll i = (ll)x; i < (ll)limit; i++)
#define REP(i, x, limit) for (ll i = (ll)x; i <= (ll)limit; i++)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define el '\n'
#define spa " "
#define Yes cout << "Yes" << el
#define No cout << "No" << el
#define YES cout << "YES" << el
#define NO cout << "NO" << el
#define eps (1e-10)
#define Equals(a,b) (fabs((a) - (b)) < eps )
#define debug(x) cerr << #x << " = " << x << el

const double pi = 3.141592653589793238;
const int inf = 1073741823;
const ll infl = 1LL << 60;
const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string abc = "abcdefghijklmnopqrstuvwxyz";

template<typename T1, typename T2>
std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){
    os << "{" << p.first << "," << p.second << "}";
    return os;
}

// 配列の要素を空白区切りで出力 第二引数をtrueにすると改行区切り
template<typename T> inline void print_vec(const vector<T> &v, bool split_line=false) {
    if(v.empty()){
        cout << "This vector is empty." << el;
        return;
    }
    constexpr bool isValue = is_integral<T>::value;
    for (int i = 0; i < (int)v.size(); i++) {
        if constexpr(isValue){
            if((v[i]==inf) || (v[i]==infl)) cout << 'x' << " \n"[split_line || i+1==(int)v.size()];
            else cout << v[i] << " \n"[split_line || i+1==(int)v.size()];
        }else cout << v[i] << " \n"[split_line || i+1==(int)v.size()];
    }
}

template<typename T1, typename T2> inline void print_vec(const vector<pair<T1,T2>> &v, bool split_line=false){
    if(v.empty()){
        cout << "This vector is empty." << el;
        return;
    }
    for(int i = 0; i < (int)v.size(); i++){
        cout << '{';
        auto [a,b] = v[i];
        constexpr pair<bool,bool> isValue = {is_integral<T1>::value, is_integral<T2>::value};
        if constexpr(isValue.first){
            if(a==inf || a==infl) cout << "x,";
            else cout << a << ",";
        }else cout << a << ",";
        if constexpr(isValue.second){
            if(b==inf || b==infl) cout << "x,";
            else cout << b;
        }else cout << b;
        cout << "}" << " \n"[split_line || i+1==(int)v.size()];
    }
}

template<typename T1, typename T2> inline bool chmax(T1 &a, T2 b) {
    bool compare = a < b;
    if(compare) a = b;
    return compare;
}
template<typename T1, typename T2> inline bool chmin(T1 &a, T2 b) {
    bool compare = a > b;
    if(compare) a = b;
    return compare;
}

// std::chronoを利用した時間計測用クラス
class Timer{
    chrono::system_clock::time_point start;
    public:
        Timer() : start(chrono::system_clock::now()) {}
    
        double count(){
            chrono::duration<double> Time_ = chrono::system_clock::now() - start;
            return Time_.count();
        }

        bool is_under(double x){
            return (this -> count()) < x;
        }
};

// std::uniform_int_distributionを利用した一様乱数生成クラス
class Random_Gen{
    random_device seed_gen;
    mt19937 engine;
    uniform_int_distribution<int64_t> dist;
    public:
        // Constructor [l,r]で生成する値の範囲を指定
        Random_Gen() : engine(seed_gen()) {}
        Random_Gen(int64_t l, int64_t r) : engine(seed_gen()), dist(l,r) {}
        
        // 現在の生成する値の範囲をstd::pairで返す
        pair<int64_t,int64_t> get_range(){
            return make_pair(dist.min(),dist.max());
        }
        // 生成する値の範囲を[l,r]に変更する
        void set_range(int64_t l, int64_t r){
            uniform_int_distribution<int64_t>::param_type Param(l,r);
            dist.param(Param);
        }
        // [l,r]内の一様分布の整数を返す
        int64_t gen(){
            return dist(engine);
        }
        int64_t operator()(){ return gen(); }
};

#endif
  1. 正直どのくらい速くなっているのかよくわかっていませんが、速くなるのに越したことはないです。

  2. たまにintをlong long型に変換してる人もいますが、それはさすがにやりすぎな気がします。あとllではなくlint派の人もいますね。

  3. 「厳密な理解をしていないため説明できない」が正しいですね…

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?