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

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

https://atcoder.jp/contests/abc250/tasks

## [B - Enlarged Checker Board](https://atcoder.jp/contests/abc250/tasks/abc250_b)
#### やりたいこと
複数のマスで構成されるタイルの仕様と個数が入力される。
それらをつなぎ合わせた最終的な全体をマス単位で出力しよう。
#### 入力値の取得
```kotlin
    // 入力値の取得
    val (n, a, b) = readLine()!!.split(" ").map { it.toInt() }
```
#### 全体のマス目を保持する配列の用意
タイル1つはは縦a行*横b列。そのタイルを縦n行*横n列なので、**最終的なマス目は縦(a * n)行、横(b * n)列** となる。
該当のサイズの2次元配列を用意し、全てが白で塗られているよう初期化しよう。
```kotlin
    // 全体のマス目を保持する配列
    val map = Array(n * a) { CharArray(n * b) { '.' } }
```
#### 黒いタイルのエリアを更新
左上は白いタイルで、あとは白いタイルと黒いタイルが市松模様状に並ぶ。タイルの行インデックスを r (0 <= r < n)、列インデックスを c (0 <= c < n) とすると、**黒いタイルは $r+c$ が奇数** のものとなる。タイルごとに処理をし、黒いタイルのエリアに該当するマスを黒で塗ろう。
```kotlin
    for (r in (0 until n)) {
        for (c in (0 until n)) {
            // r行、c列のタイルの処理
            if ((r + c) % 2 == 1) {
                // 黒タイルを対象とした処理
                // タイルの上辺の行
                val top = r * a
                // タイルの左端の列
                val left = c * b
                for (y in (top until top + a)) {
                    for (x in (left until left + b)) {
                        // 黒タイルのマスごとの処理
                        map[y][x] = '#'
                    }
                }
            }
        }
    }
```
#### サンプルコード
```kotlin:main.kt
fun main(args: Array<String>) {
    // 入力値の取得
    val (n, a, b) = readLine()!!.split(" ").map { it.toInt() }
    // 全体のマス目を保持する配列
    val map = Array(n * a) { CharArray(n * b) { '.' } }
    for (r in (0 until n)) {
        for (c in (0 until n)) {
            // r行、c列のタイルの処理
            if ((r + c) % 2 == 1) {
                // 黒タイルを対象とした処理
                // タイルの上辺の行
                val top = r * a
                // タイルの左端の列
                val left = c * b
                for (y in (top until top + a)) {
                    for (x in (left until left + b)) {
                        // 黒タイルのマスごとの処理
                        map[y][x] = '#'
                    }
                }
            }
        }
    }
    // 答えを出力
    map.forEach { println(it.joinToString("")) }
}
```
## [C - Adjacent Swaps](https://atcoder.jp/contests/abc250/tasks/abc250_c)
#### やりたいこと
操作を指示する入力は位置ではなくボールに書かれた数字で指定される。位置からボールを特定する配列と、ボール（に書かれた数字）から位置を特定する配列の **2つの配列** を用意してボールを管理しよう。
#### 入力値の取得
```kotlin
    // 入力値の取得
    val (n, q) = readLine()!!.split(" ").map { it.toInt() }
    repeat(q) {
        val x = readLine()!!.toInt()
        // ボール入れ替え処理
    }
```
#### 位置からボールを特定する配列を用意
```kotlin
    // 位置からボールを特定する配列
    val balls = (1..n).toList().toIntArray()
```

#### ボールに書かれた数字から位置を特定する配列の用意
ボールに書かれた数字をインデックスとし、ボールの位置を保持する配列を用意しよう。
```kotlin
    // ボールに書かれた数字から位置を特定する配列
    val numToIndex = (listOf(0) + (0 until n)).toIntArray()
```
:::note info
ボールに書かれた数字は1~nの範囲とりますが、配列のインデックスは0はじまりのため、インデックス範囲が0~nとなるよう要素数(n+1)の配列を作成しています。先頭の要素は使用しません。
:::
#### ボールの入れ替え対象の位置と番号を特定
```kotlin
        val x = readLine()!!.toInt()
        // ボール1の位置
        val idx1 = numToIndex[x]
        // 入れ替え対象となるボール2の位置
        val idx2 = if (idx1 == balls.lastIndex) idx1 - 1 else idx1 + 1
        // ボール2に書かれたナンバー
        val x2 = balls[idx2]
```
#### サンプルコード
```kotlin:main.kt
fun main(args: Array<String>) {
    // 入力値の取得
    val (n, q) = readLine()!!.split(" ").map { it.toInt() }
    // 位置からボールを特定する配列
    val balls = (1..n).toList().toIntArray()
    // ボールに書かれた数字から位置を特定する配列
    val numToIndex = (listOf(0) + (0 until n)).toIntArray()
    repeat(q) {
        // ボール入れ替え処理
        val x = readLine()!!.toInt()
        // ボール1の位置
        val idx1 = numToIndex[x]
        // 入れ替え対象となるボール2の位置
        val idx2 = if (idx1 == balls.lastIndex) idx1 - 1 else idx1 + 1
        // ボール2に書かれたナンバー
        val x2 = balls[idx2]
        // 入れ替え
        swap(x, x2, numToIndex)
        swap(idx1, idx2, balls)
    }
    println(balls.joinToString(" "))
}

fun swap(idx1: Int, idx2: Int, target: IntArray) {
    val tmp = target[idx1]
    target[idx1] = target[idx2]
    target[idx2] = tmp
}
```