あるエンジニアのAtCoder奮闘記

東京都港区にあるアミフィアブル株式会社のエンジニアが、AtCoderで解いた問題について振り返ったりしていく会社公認のブログです。

ABC121 C Energy Drink Collector,D XOR WorldをKotlinで解いてみた話

irisruneです。自己紹介でも軽く触れましたがKotlinが面白そうだったので過去問はだいたいKotlinでやります。

今日のテーマはちょっと軽めですがABC121のC問題とD問題。あと一応AtCoderで使うKotlinについて。

ABC121-C

atcoder.jp

やるだけソートの実装力が9割くらいの問題です。

class Store(val a : Long, val b : Long)

fun main(args: Array<String>){
    var(n, m) = readLine()!!.split(" ").map(String::toLong)
    var l = mutableListOf<Store>()
    for(i in 1..n){
        val (a, b) = readLine()!!.split(" ").map(String::toLong)
        l.add(Store(a, b))
    }
    l.sortBy { it.a }
    var sum = 0L
    l.forEach{
        sum += it.a * listOf(it.b, m).min()!!
        m = listOf(0, m - it.b).max()!!
    }
    println(sum)
}

想定解と同じだしアルゴリズム面で言うこともあまりないと思うので簡単なコードレビューを。

  • MutableListは別にvarにする必要はないのでvalにするべき。
  • 単純な整数2つの組ならクラスを作るなんて仰々しいことをしなくてもPairでなんとかなる。
  • 入力値のmを直接変化させるのは微妙?forEach部分をメソッドに分離してmを値渡しすればすっきりしそう。

ABC121-D

atcoder.jp

XORの性質を理解しているかどうか…というよりはf(0,X)を求める発想ができるかの方が強いと思います。D問題にしては比較的簡単な方です。

fun f(x : Long) : Long{
    return when(x % 4){
        0L -> x
        1L -> 1L
        2L -> x + 1L
        else -> 0L
    }
}

fun main(args: Array<String>){
    var (a, b) = readLine()!!.split(" ").map(String::toLong)
    println(f(a - 1).xor(f(b)))
}

解法に行き着く過程としてはこんな感じでした。

  1. 愚直にやるのはO(X)時間かかるので無理。
  2. O(1)時間で解けるf(X)を使ってf(B)-f(A)みたいに表せるのでは?
  3. XORの性質上2.はだいたい正しい。
  4. f(X)X=0,1,\dotsで列挙したら法則性が見つかったので解けた。

解説ではf(X)は排他的論理和の性質から数学的に導けるとありましたが、いずれにせよ(X\mod 4)での場合分けに行き着くと思います((X\mod 2)(\lfloor \frac{X}{2}\rfloor \mod 2)とで二回分岐するのも本質的に同じなので)。

あとはコードレビュー。

  • (a, b)はvalにするべき。
  • (x % 4)は(x % 4L)にするべき。

型関連はバグの原因になるので気を付けましょう。今回はセーフでした。

(pure)Kotlin(v1.0)のポイント

(2019/03/05現在)AtCoderではKotlin1.0しか使えません。これはどの辺に影響してくるかというと例えば

    val minA = minOf(A1, A2)

が使えないので、(pure)Kotlinで書くならば

    val minA = listOf(A1, A2).min()

という形に。Java関数を使えば別に不自由しないと思うんですがせっかくなのでJava関数は(なるべく)使わない方針で。

でもkotlin.mathが使えないのは代替案が思いつかないのでjava.lang.Math使います。つらい。