0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AtCoder B,C問題をKotlinで解こう - ABC255

Posted at

当記事ではAtCoder、ABCのB問題ならびにC問題(時々D問題も)のKotlinでの解法を超初心者向けに詳細に解説します。

B - Light It Up

やりたいこと

人(0~N-1、配列に入れることを考慮して0始まりとする)のそれぞれについて、最も近くにいる明かりを持った人との距離 を算出しよう。なお、本人が明かりを持っている場合は0とする。

位置情報を保持するクラスの作成

人の位置を保持し、最も近くにいる明かりを持った人間の検出をスムーズにするため、位置情報クラスを作成しよう。

// 位置情報を保持するクラス
class Loc(private val x: Int, private val y: Int) {
    // 他の位置情報との距離を求めるメソッド
    fun diff(other: Loc): Double {
        return ((x - other.x).let { it.toLong() * it } + (y - other.y).let { it.toLong() * it }).let { Math.sqrt(it.toDouble()) }
    }
}

入力値の取得

    // 入力値の取得
    val (n, k) = readLine()!!.split(" ").map { it.toInt() }
    val a = readLine()!!.split(" ").map { it.toInt() - 1 }
    val xy = (1..n).map { readLine()!!.split(" ").map { it.toInt() }.let { Loc(it[0], it[1]) } }

明かりを持った人間との距離

人(0~n-1)について、 最も近くにいる明かりを持った人間 との距離を取得しよう。

    // 人(0~n-1)のそれぞれ最も近い「明かりを持った人」との距離を求める。
    val farToLights = xy.map { target -> a.map { xy[it].diff(target) }.min()!! }

サンプルコード

main.kt
fun main(args: Array<String>) {
    // 入力値の取得
    val (n, k) = readLine()!!.split(" ").map { it.toInt() }
    val a = readLine()!!.split(" ").map { it.toInt() - 1 }
    val xy = (1..n).map { readLine()!!.split(" ").map { it.toInt() }.let { Loc(it[0], it[1]) } }

    // 人(0~n-1)のそれぞれ最も近い「明かりを持った人」との距離を求める。
    val farToLights = xy.map { target -> a.map { xy[it].diff(target) }.min()!! }

    // 上記の最大値が答えとなる
    println(farToLights.max())

}

// 位置情報を保持するクラス
class Loc(private val x: Int, private val y: Int) {
    // 他の位置情報との距離を求めるメソッド
    fun diff(other: Loc): Double {
        return ((x - other.x).let { it.toLong() * it } + (y - other.y).let { it.toLong() * it }).let { Math.sqrt(it.toDouble()) }
    }
}

C - ±1 Operation 1

やりたいこと

等差数列Sに含まれる数値のうち、Xに最も近いものとXの差(の絶対値)を求めよう。

入力値の取得

    val (x, a, d, n) = readLine()!!.split(" ").map { it.toLong() }

等差数列Sの最大値と最小値を決めよう

等差数列Sの初項はa、公差はd、要素数はnとなる。そこからSの最終項は $a + d(n - 1)$ となることが分かる。
等差数列Sの最大値と最小値を決定しよう。公差はマイナスになることがあるので、その場合は初項と最終項を入れ替えて、公差の絶対値を後の処理として使用しよう。

    // 等差数列Sの最終項の取得
    val last = a + (d * (n - 1))

    // 等差数列Sの最小値の取得
    val fixedFirst = if (d >= 0) a else last
    // 等差数列Sの最大値の取得
    val fixedLast = if (d >= 0) last else a

    // 最適化された等差数列の公差
    val fixedD = Math.abs(d)

場合分けをして処理しよう

等差数列の数値が1種類のみの場合(要素数が1または交差が0)
    if (fixedFirst == fixedLast) {
        // 等差数列Sの要素が一つだけの場合
        return Math.abs(x - fixedFirst)
    }
xが等差数列Sの範囲内に含まれない場合

Sの最大値と最小値、それぞれの差(の絶対値)の内、小さい方が答えとなる。

    if (fixedFirst == fixedLast) {
        // 等差数列Sの要素が一つだけの場合
        return Math.abs(x - fixedFirst)
    } else if (x !in fixedFirst..fixedLast) {
        // x が等差数列の最小〜最大の範囲に含まれない場合
        return Math.min(Math.abs(fixedFirst - x), Math.abs(fixedLast - x))
    }
xが等差数列Sの範囲内に含まれる場合

Sに含まれる要素の内、x以下の最大値とx以降の最小値を求め、それらとの差の絶対値を求めよう。

    if (fixedFirst == fixedLast) {
        // 等差数列Sの要素が一つだけの場合
        return Math.abs(x - fixedFirst)
    } else if (x !in fixedFirst..fixedLast) {
        // x が等差数列の最小〜最大の範囲に含まれない場合
        return Math.min(Math.abs(fixedFirst - x), Math.abs(fixedLast - x))
    } else {
        // 等差数列Sに含まれる数値から、X以下で最大の数値を取得する
        val near1 = ((x - fixedFirst) / fixedD) * fixedD + fixedFirst

        // 等差数列Sに含まれる数値から、X以上で最小の数値を取得する
        val near2 = fixedLast - ((fixedLast - x) / fixedD) * fixedD

        return Math.min(Math.abs(x - near1), Math.abs(near2 - x))
    }

サンプルコード

main.kt
fun main(args: Array<String>) {
    println(getAns())
}

fun getAns(): Long {
    val (x, a, d, n) = readLine()!!.split(" ").map { it.toLong() }

    // 等差数列Sの最終項の取得
    val last = a + (d * (n - 1))

    // 等差数列Sの最小値の取得
    val fixedFirst = if (d >= 0) a else last
    // 等差数列Sの最大値の取得
    val fixedLast = if (d >= 0) last else a

    // 最適化された等差数列の公差
    val fixedD = Math.abs(d)

    if (fixedFirst == fixedLast) {
        // 等差数列Sの要素が一つだけの場合
        return Math.abs(x - fixedFirst)
    } else if (x !in fixedFirst..fixedLast) {
        // x が等差数列の最小〜最大の範囲に含まれない場合
        return Math.min(Math.abs(fixedFirst - x), Math.abs(fixedLast - x))
    } else {
        // 等差数列Sに含まれる数値から、X以下で最大の数値を取得する
        val near1 = ((x - fixedFirst) / fixedD) * fixedD + fixedFirst

        // 等差数列Sに含まれる数値から、X以上で最小の数値を取得する
        val near2 = fixedLast - ((fixedLast - x) / fixedD) * fixedD

        return Math.min(Math.abs(x - near1), Math.abs(near2 - x))
    }
}
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?