はるすえすしーのぶろぐ

ブログのないようがないよう

JuliaでAtCoderをしよう!

※この記事は古い情報です。投稿時点でのAtCoderのJuliaのバージョンはv0.5であり、一部プログラムが動作しない可能性があります。環境もAtomよりVSCodeをお勧めします(個人的に)。また後で書き直します。

まえがき

お久しぶりです。まぁじです。
この暇な春休み。積みっぱなしの本、クリア前で放棄したゲーム、途中でやめた開発…といろいろやることはありますが、皆さんいかがお過ごしでしょうか。
僕はJuliaでAtCoderの問題(過去問)を解いています。最近JuliaのLanguage Rankingで5位になりました。※3/16に4位になりました
これは5位になった時のツイート(画像はAtCoder Problemsより)ですが、目標が5位になっている気がします。最近視力が低下しているのでそのせいだと思いますが。

このブログは「あなたは幸せですか?幸福になりたいですか?そんな罪深きあなたもJuliaは幸せに導いてくれます…」といういわゆる宗教勧誘です。
ただしJuliaはあくまで「Julia Language」というプログラミング言語を指しており、そのほかの人物等を指しているわけではないことをここに記しておきます。(ほかのJuliaが気になったらプライベートモードで検索してみてね)

長いので以下目次。

Juliaって?

Wikipediaより。

Julia(ジュリア)は、汎用プログラミング言語水準から高度の計算科学や数値解析水準まで対処するよう設計された高水準言語かつ仕様記述言語、及び動的プログラミング言語である。並行計算、並列計算、分散コンピューティング、及びAdapter パターン不要でC言語FORTRANへのForeign function interfaceに対応している。ガベージコレクションを行い先行評価を用いるほか、浮動小数点数計算、線型代数学、高速フーリエ変換正規表現照合のライブラリを利用できる。
Julia(プログラミング言語) - Wikipedia

「C並みに速く、MATLAB並みに行列計算ができ、Python並みに書きやすく、R並みにデータ処理に強い言語」ってJuliaプログラミングクックブック(オライリージャパン社)の帯に書いてありました。まぁ現在の競プロ環境における強さは微妙なんですが。

Juliaの入れ方

  • Julia公式サイト(Download Julia)からダウンロード。Current stable releaseの64bit版がいいと思います。(2020/3/7現在、v1.3.1)
  • コマンドプロンプトで下の画像みたいになって、かつ「julia>Pkg.add("Atom")」ができたらだいたいOKです。できなければ全て消去してもう一度インストールしてください。

Juliaの起動イメージ
ちなみに、エディタは何でもいいのですがおすすめはAtom+Juno(パッケージ)です。自動補完が一番効きます。

JuliaでAtCoder

基本形

Julia Language OwnerのT49E2さんのたのしいAtCoder Julia編 - Qiitaを参考にしてます。
readline()関数は1行読み取り、split()関数は空白(区切り文字は指定可)で分割、chomp関数は文字列から改行を取り除く関数です。
※3/22 ちょっと変更

parseInt(x) = parse(Int, x)
parseBigInt(x) = parse(BigInt, x)
parseFloat(x) = parse(Float64, x)
parseBigFloat(x) = parse(BigFloat, x)
parseMap(x::Array{SubString{String},1}) = map(parseInt, x)

function main()
    # 整数の入力
    n=parseInt(readline())
    # 複数の整数の入力
    a=parseMap(split(readline()))
    # 文字列の入力
    s=chomp(readline())
    # 複数の文字列の入力
    arr_s=split(readline())

    # 改行ありの出力
    println(a)
    # 改行なしの出力
    print(s)
end
main()
演算

基本的にはほかの言語と同じです。違う点だけ。

julia> a,b=3,2
(3, 2)

# 実数での除算
julia> a/b
1.5
julia> b\a
1.5

# 切り捨て除算(Pythonで言う"//",0に向かって切り捨て)
julia> div(a,b)
1

# 切り捨て除算は"÷"でも可能
julia> a÷b
1

# 切り上げ除算
julia> cld(a,b)
2

# べき乗(Pythonでは"**"、pow関数はない)
julia> a^b
9

# ルート
julia> sqrt(a)
1.7320508075688772

# 1/2乗としても答えは同じになるが、若干遅い
julia> a^0.5
1.7320508075688772

# 小数での切り上げ、切り捨て
julia> ceil(3.1415)
4.0
julia> floor(3.1415)
3.0

# truncで値を丸める、第一引数をIntにするとIntで返す
julia> trunc(Int,3.1415)
3
julia> trunc(Int,ceil(3.1415))
4
julia> trunc(Int,floor(3.1415))
3
if文、for文

終わりに"end"と書き、":"やタブは必要ありません。

# 1~10を出力(pythonのrangeと違い、終点を含む)
for i = 1:10
    println(i)
end

# こっちでもOK、速さはあまり変わらないです
for i in 1:10
    println(i)
end

#FizzBuzz問題(一番単純なコード)
for i = 1:100
    if i%15==0
        println("FizzBuzz")
    elseif i%3==0
        println("Fizz")
    elseif i%5==0
        println("Buzz")
    else
        println(i)
    end
end
知っておくこと

ちなみに配列のインデックスは1から始まります。たまに混乱します。
あと、時間計測は"@time 関数名"で出来ます。for文も同様です。

# 文字列の結合は"+"ではなく"*"
julia> "Hals"*"SC"
"HalsSC"
# ただしString*Charを行うとAtCoderではエラーが発生するのでStringに変換するstring関数を使ったほうがいい
julia> print("Hal"*'s')
ERROR: LoadError: MethodError: no method matching *(::String, ::Char)
Closest candidates are:
  *(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:138
  *(::AbstractString, !Matched::AbstractString...) at strings/basic.jl:84
 in include_from_node1(::String) at ./loading.jl:488
 in process_options(::Base.JLOptions) at ./client.jl:262
 in _start() at ./client.jl:318
while loading /imojudge/Main.jl, in expression starting on line 1

julia> print("Hal"*string('s'))
"Hals"

# 文字列の結合(上の*を使う方法より遅い)
julia> join(["Hals",'_',"SC"])
"Hals_SC"

# 空白区切りでの出力もできる
julia> join(["abc","def"]," ")
"abc def"

# 非破壊的なソート(pythonでいうsorted、ソートした配列を返す)
arr=[3,2,5,1,2]
sorted=sort(arr)
println(sorted)

# 破壊的なソート(配列そのものをソートする)
sort!(arr)
println(arr)

# タプルの1要素目について逆順で破壊的なソート(abc128_bに似た問題で使ったような…)
numbers=Tuple{Int,String}[(5,"ksun48"),(2,"apiad"),(1,"tourist"),(4,"ecnerwal"),(3,"Um_nik")]
sort!(numbers,by=x->x[1],rev=true)
println(numbers)
#出力:Tuple{Int64,String}[(5, "ksun48"), (4, "ecnerwal"), (3, "Um_nik"), (2, "apiad"), (1, "tourist")]

# 配列の重複する要素の削除(Setを経由させることで削除しています、遅いかも)
array=[3,1,4,1,5,9,2,6,5]
collect(Set(array))

# 文字列を文字列のままソート(ex:"bca"->"abc")
s="bca"
join(sort(collect(s)))

# 数字を左からゼロ埋めした文字列を作る
number=5
keta=6
lpad(number,keta,"0")
おわりに

あれも書いておこう、これも書いておこうとしたら膨大な文字数になってしまいました。それでもTupleやDictなどの型の説明もしていないので、自分で調べてみてください。あとはAtCoderのJuliaのバージョンがv0.5なので(2020/3/8現在)、はやめにv1.3.1が全体で使えるようになるとコンテストにも出やすいかな~って思います。
興味を持たれた方はぜひJuliaをやってみてください!調べるときは検索履歴に気を付けて!