最適解ではありません
知見はいつでも募集中
いろんな人のコードを見よう
oj
oj を入れておく
以下の内容のいくつかは oj と重複している
エディタ
一番よく聞くので vscode
template
template-dir
にデフォルトで欲しいファイルを全て置いておく
問題を解く時はこのディレクトリの中身を丸々コピーする(後述)
b.cpp
メインのコード
#include <bits/stdc++.h>
や REP
マクロなど欲しいもの全部書いておく
pragma region を用いることでエディタ上ではこれらのテンプレートは全て隠して置ける
tle.cpp
愚直解用のコード
b.cpp と同じ準備をしておく
make_random.py
入力生成をするコード
便利な関数を書いておく
例 INTS(l,r,n)
: 各要素が 以上 以下の、長さ の配列を返す
木やグラフ、distinct な数列などを作る関数なども書いておくと良い
関数は全てさらに別の library.py
に書いておけば import
を書くだけで良くなる
cnt.txt
自分で新たに作ったサンプルの個数を数えるようのファイル
を書いておく
.bashrc
alias や関数を書いておくことで、ターミナルで色々実行できるようにする
PATH
と書いてある部分は実際には絶対パスが入る
基本
alias g++='g++-11 -std=gnu++17 -D=__LOCAL -O2 -I PATH/acl -I PATH/local' alias G='g++ b.cpp' alias GTLE='g++ tle.cpp -o tle.out' alias a='./a.out' alias TLE='code tle.cpp' alias RA='code make_random.py' alias ..='cd ../' mkcd(){ mkdir $1 cd $1 }
g++
の -D=__LOCAL
で __LOCAL
を define させてる理由は後述
新しい問題を解く時
np(){ mkcd $1 cp -r PATH/template-dir/ ./ chrome_cpy oj d "$(pbpaste)" code b.cpp }
例えば np a
と打つと
- ディレクトリ
a
を作成しそこに移動 a
にtemplate-dir
の中身がコピーされるchrome_cpy
は applescript を用いて現在 Google Chrome で開いているページのリンクをクリップボードにコピーする alias (中身省略)oj d "$(pbpaste)"
によってそのリンクのサンプルをダウンロードするb.cpp
を開く
愚直解との比較
C(){ for _ in $(seq $1);do python make_random.py > input.txt ./a.out < input.txt > wrong.txt ./tle.out < input.txt > correct.txt if [ "$(diff --brief wrong.txt correct.txt)" = "Files wrong.txt and correct.txt differ" ];then echo "$(<input.txt)" echo "Wrong:" echo "$(<wrong.txt)" echo "Correct:" echo "$(<correct.txt)" cnt=$(cat cnt.txt) cnt=$(( $cnt + 1)) echo "This sample is x-sample${cnt}" mv input.txt test/x-sample${cnt}.in mv correct.txt test/x-sample${cnt}.out echo $cnt > cnt.txt break fi done }
ランダムケースを生成し、./a.out
と ./tle.out
の結果を比較
結果が異なっていた場合、入力と二つの結果を出力したのち、そのケースを test/x-sample1
として追加する(添字は毎回増える)
従って、以降 oj t
をした場合既存の sample に加えて新しい hack ケースもチェックしてくれる
以上のことを C n
で hack ケースが見つかるまで実行する
ただし は実行上限回数で、hack ケースが見つからないまま 回試し終わった場合そこで止まる
提出
TS(){ out=false for f in test/*.in;do result=$(diff --brief <(./a.out < $f) ${f/.in/.out}) if [ ${#result} -ne 0 ];then out=true break fi done if "${out}";then oj t else oj s b.cpp --yes fi }
提出用の関数
test
内全て一致するか試し、撃墜ケースがあれば出力、無ければ提出をする
後でコンパイル機能付きのも作る
debug
local/debug
に以下を書いておく
別に b.cpp に直接書いても良いが、local でしか実行しない関数なので #include した方がかっこいいと思う
# define debug(...) debug_internal(#__VA_ARGS__, __VA_ARGS__) template <class T, class... Args> void debug_internal(const char* s, T&& first, Args&&... args) { constexpr const char* open_brakets = sizeof...(args) == 0 ? "" : "("; constexpr const char* close_brakets = sizeof...(args) == 0 ? "" : ")"; std::cerr << open_brakets << s << close_brakets << ": " << open_brakets << std::forward<T>(first); ((std::cerr << ", " << std::forward<Args>(args)), ...); std::cerr << close_brakets << endl; }
以下のようなことが出来る
//テンプレート int main(){ int a=3,b=4; char c='a'; double d=3.5; string s="hoge"; debug(a,b,c,d,s); } // (a,b,c,d,s): (3, 4, a, 3.5, hoge) と出力される
また、出力を自分で定義しておくことで以下のように他の型も扱えるようにしてある
//テンプレート int main(){ vector<vector<int>> v(5); REP(i,5)REP(j,i*2)v[i].push_back(i+j); pair<int,int> P={1,2}; set<int> se; REP(i,10)if(i&1)se.insert(i); map<vector<int>,int> mp; for(auto ve:v)mp[ve]=ve.size(); debug(v); // v: [[],[1,2],[2,3,4,5],[3,4,5,6,7,8],[4,5,6,7,8,9,10,11]] debug(se,P); // (se,P): ({1,3,5,7,9}, [1,2]) debug(mp); // mp: [[]:0][[1,2]:2][[2,3,4,5]:4][[3,4,5,6,7,8]:6][[4,5,6,7,8,9,10,11]:8] }
提出の際には働いてほしく無いので、手元のコンパイル時に __LOCAL
を define させておき、コードに以下を書いておく
#ifdef __LOCAL #include <debug> #else #define debug(...) void(0) #endif
手元で debug の結果を見たく無い時は 2>/dev/null でエラー出力を無視する