LoginSignup
7
3

More than 1 year has passed since last update.

【裏技】AtCoderでコンパイラコマンドを変更する

Last updated at Posted at 2021-11-07

はじめに

AtCoderでコンパイラコマンドを変更できたらなあ,ということはありませんか?
そんなときのための裏技です.

フォーマット

以下をPythonで実行することで,自由なコンパイラコマンドでコードをコンパイルできます.

import sys
import os

def run():
  # 実行前であることを判定
  if sys.argv[-1] == 'ONLINE_JUDGE':
    import subprocess

    # ファイルの名前
    filename = 'mycode.cpp'
    # コンパイラコマンド
    command = 'g++ -std=gnu++17 mycode.cpp'
    # コード
    mycode = r'''
#include <bits/stdc++.h>
using namespace std;
int main() {
  cout << "Hello world!" << endl;
}
  '''

    # ファイルを作成し,コードを記述
    with open(filename, 'w') as f:
      f.write(mycode)

    # コンパイルエラーがerror.txtに出力されるようにコンパイルする
    with open('error.txt', 'w') as f:
      exit_code = subprocess.run(command.split(), stderr = f).returncode

    # exit codeが0以外ならfailed.txtを作成
    if exit_code:
      with open('failed.txt', 'w') as f:
        pass
    exit()

  # failed.txtが存在したら標準エラー出力にerror.txtを記述
  if os.path.exists('failed.txt'):
    with open('error.txt') as f:
      sys.stderr.write(f.read())
      exit(1)

  # 実行コマンド
  os.system('./a.out')

run()

使い方

変更する必要のある場所は4つです.

  • filename:ファイルの名前
  • command:コンパイラコマンド
  • mycode:コードの本体
  • 最後のos.systemの引数:実行コマンド

これさえ用意すればあとはコンパイルしてくれます.

仕組み

Language Test 202001 によれば,AtCoderのPythonではテストケース実行前に次のようなコマンドでコードが実行されます.

python3.8 {dirname}/{basename} ONLINE_JUDGE 2>/dev/null

そして,この ONLINE_JUDGE コマンドライン引数は,テストケース実行時には無くなります.

これを利用すれば,ONLINE_JUDGEの有無でテストケース実行前かを判定できます!!(おそらくこれはPython限定です)

フォーマットでは,if sys.argv[-1] == 'ONLINE_JUDGE':として実行前にコンパイルしています.

また,コンパイルエラーが出た場合もerror.txtに保存しておいてちゃんと出力されるようになっています.

応用例

Clangで bits/stdc++.h を使ったり最適化したりする

AtCoderでGCCよりClangが劣っていると言われやすい点を解消できます.

AtCoderのClangは libc++ という標準ライブラリを使っているので,bits/stdc++.h がありません.

そこで,AtCoderのコンパイラコマンド(Language Test 202001)から stdlib=libc++ を取り除けば,GCCと同じ libstdc++ となり,bits/stdc++.h を使えるようになります.

同様に,Clangではコードからは #pragma clang optimize on という最適化しかできませんでしたが,コンパイラコマンドをいじることで詳細まで最適化できるようになります.

スタックサイズを変更

稀にスタックオーバーフローを起こす場合は,先に次のコードを実行してからコンパイルさせれば通るかもしれません.

os.system('ulimit -s unlimited')

ただし,AtCoderではスタックサイズが既にギリギリなので,colun法 の方が無難です.

Cythonのコンパイル

AtCoderのCythonは,Cにコンパイルされるので,C++のSTLが使えなくなってしまいます.

そこで,自分でコンパイルします.

Cythonのコンパイルやその他については以下にまとめました:

NumbaAOT

Numbaは、通常ではコンパイルに400msほどかかり,メモリ消費もそこそこ多いため,JuliaやPyPyと比較して見劣りします.

そこでNumbaAOT(事前コンパイル)を使うと,メモリ消費がPyPyより少なく,起動時間もNumpyのimportの100msだけとなり魅力的になります.

以下の記事に使い方が載っています.

その他

  • C++で-fconstexpr-loop-limit=10000000000などのオプションの追加
  • Python/PyPyの事前コンパイル(py_compile)
  • Pythonのコンパイル時計算(ファイルの読み込みが重いので実用的でない).

おわりに

実行前に処理を行えることは色々と応用が効くので,新しいアイディアがあるかもしれません.

最後まで読んでいただきありがとうございました.

参考

AtCoderでCythonの力を開放する魔術詠唱 を参考に作成しました.

7
3
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
7
3