yu/logs/*

技術メモ など

Kotlin for competitive programming(競技プログラミングのためのKotlin)を読んでみた

KotlinでAtCoder参加中(灰色)です。

言語仕様を確認しに行こうと久々にKotlin Programming Languageを見に行ったところ、「Kotlin for competitive programming | Kotlin競技プログラミングのためのKotlin)」というページがあったので、少し読んでみました。

備考

  • 灰色コーダーなので競技プログラミングの知見はあまり無い
  • Kotlinも趣味で触ってる程度なのでそれほど知見は無い
  • 英語も特に読めるわけではないのでDeepL翻訳にかけてるだけ
  • 気になった部分だけ抜粋して翻訳して見ていっています

Kotlin for competitive programming

競技プログラミングのためのKotlin

ページの導入部分です

抜粋1

原文

While not being specifically designed for competitive programming, Kotlin incidentally fits well in this domain, reducing the typical amount of boilerplate that a programmer needs to write and read while working with the code almost to the level offered by dynamically-typed scripting languages, while having tooling and performance of a statically-typed language.

翻訳

Kotlinは特に競技プログラミングのために設計されたわけではありませんが、付随的にこの領域にうまく適合し、プログラマがコードを扱う際に書いたり読んだりする必要のある典型的な定型文を、動的型付けスクリプト言語が提供するレベルまでほぼ減らし、かつ静的型付け言語のツールや性能を備えているのです。

感想

おそらく競技プログラミング経験者 && Kotlin未経験者に向けた文章かな?動的型付けスクリプト言語の感覚でかけるけど静的型付け言語としてのメリットを具備しているよというのが売り文句になってる感じかな。

抜粋2

原文

In competitive programming, a single project is usually created and each problem's solution is written in a single source file.

翻訳

対戦型プログラミングでは、通常1つのプロジェクトを作成し、各問題の解決策を1つのソースファイルに記述します。

感想

(1問ごとにファイル切るの面倒で1コンテスト1ファイルにしちゃってた) github.com

Simple example: Reachable Numbers problem

簡単な例:リーチャブルナンバーズ問題(?)

要約
  • (簡単な問題を解きながら、Kotlinでの競プロでの書き方を例示)
  • 命令型/関数型のどちらでも書けるよ
    • 末尾再帰を使ったりも
  • 型推論をしているので、だいたいは型の記述は省略可能だけど、静的型付けになってるよ
  • KotlinはデフォルトでJVM上で動作するので、ArrayList、HashMap/HashSet、TreeMap/TreeSetなどの豊富なコレクションライブラリが扱えるよ
  • readLine() 関数はString?型でnullableなので、!!(not-null assertion)演算子を使うよ*1*2
    • 競技プログラミングでは、入力の書式を間違えた場合を処理する必要はないよ
      • (実際の入力は問題文の入力指定から外れることはありえないので)
  • 競プロでは事前に記載したコードの使用が認められているので、ヘルパー関数を用意することができるよ
    • private fun readInt() = readLn()!!.toInt() みたいな*3
    • privateにしておくと、同じパッケージ内で定義が重複してもエラーにならないようにできるよ
感想
  • !!演算子はKotlinのnull安全のページ(Null safety | Kotlin)とかだとぬるぽ愛好家向けの選択肢とか書かれてるのでコンテストで使いながらも少しもやもやしてたんだけれど、公式で競プログラミングでは考慮しなくていいよみたいな雰囲気で書かれていて勝手に安心しました。

Functional operators example: Long Number problem

関数型演算子の例 長さの問題

要約
感想
  • 関数型チックな書き方にあまり習熟できてないので個人的にもう少し活用できるようにしたいと思いました。

More tips and tricks

その他のヒントとコツ

要約
  • val (n, k) = readLine()!!.split(" ").map { it.toInt() }.toInt() みたいな形で分割代入ができるよ*4
  • KotlinはJVMを相互運用できるのでjava.util.Scannerクラスを使用できるけど、Kotlinのsplit(" ").map{ it.toInt() }で処理されるのでめちゃめちゃ遅くなるよ
    • (105くらいで2秒の制限時間に収まらなくなる可能性がある)
  • 105行以上を出力しようとするとき、println(...)だと遅くなるよ
    • 配列やリストから出力するなら、println(a.joinToString("\n")) のようにした方が早いよ
感想
  • joinToString(...)は丁度探していたので参考になった
  • ちょっと英語力が足りてなくて標準入力のところが特にちゃんと読解できていないかもしれない

Learning Kotlin

Kotlinの学習

要約
  • WebのリファレンスやKotlin Koansで学べるよ

個人的まとめ

  • 標準入出力の部分は、まだその部分が問題になるようなところまで到達してないけど、後々役立ちそう
  • 関数型の書き方で良い感じに書けそうな気配があるので、もう少しお勉強しておきたい

*1:ページ上だと「null-assertion operator」となってるけど、たぶんassetionしてるのはnot-nullのはずなので

*2:Kotlin1.6.0以上だとreadLine()!! が readln() になるみたい。AtCoderでは2022.6.19時点では1.3.71なので、まだ先かな

*3:原文だとreadLn().toInt()となっているけど、前段のprivate fun readLn() = readLine()!!が抜けている気がする

*4:ちなみに分割代入できるのは5つまでのようで、ABC256C問題の入力のように6変数に分割代入しようとすると怒られました