当記事では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()!! }
サンプルコード
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))
}
サンプルコード
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))
}
}