AtCoder ABC310 解法(A ~ E) Ruby & Kotlin

# 解法

## [A - Order Something Else](https://atcoder.jp/contests/abc310/tasks/abc310_a)

|[公式解説](https://atcoder.jp/contests/abc310/tasks/abc310_a/editorial)|
|-|

| Difficulty | Solve Prob | Solve Time |
| :---: | :---: | :---: |
| 23 | > 99 % | 4 mins |

### Ruby

```ruby:abc310_a.rb
N, P, Q = gets.split.map(&:to_i)
D = gets.split.map(&:to_i)
puts [D.min + Q, P].min
```

### Kotlin

```kotlin:abc310_a.kt
fun main() {
  val (N, P, Q) = readLine()!!.split(" ").map(String::toInt)
  val D = readLine()!!.split(" ").map(String::toInt)
  println(Math.min(P, D.min()!! + Q))
}
```

## [B - Strictly Superior](https://atcoder.jp/contests/abc310/tasks/abc310_b)

|[公式解説](https://atcoder.jp/contests/abc310/tasks/abc310_b/editorial)|
|-|

| Difficulty | Solve Prob | Solve Time |
| :---: | :---: | :---: |
| 226 | 96 % | 19 mins |


### Ruby

```ruby:abc310_b.rb
N, M = gets.split.map(&:to_i)
# あらかじめjの候補を昇順で並び替えて置く
# Pi >= Pj && Ci <= Cj となる順
PCF = Array.new(N) { gets.split.map(&:to_i) }.sort_by { [_1[0], -_1[1]] }

N.times do |j|
  (j + 1).upto(N - 1) do |i|
    pj, cj, *fj = PCF[j]
    pi, ci, *fi = PCF[i]
    # fiとfjの和集合の数がfjの数を超える場合、上位互換になり得ない
    next if (fi | fj).size > cj
    if pi > pj || ci < cj
      puts "Yes"
      exit
    end
  end
end
puts "No"
```

### Kotlin

```kotlin:abc310_b.kt
fun main() {
  val (N, M) = readLine()!!.split(" ").map(String::toInt)
  val PCF = MutableList(N) { readLine()!!.split(" ").map(String::toInt) }

  // あらかじめjの候補を昇順で並び替えて置く
  // Pi >= Pj && Ci <= Cj となる順
  PCF.sortWith(compareBy({ it[0] }, { - it[1] }))

  for (j in 0 .. N - 2) {
    for (i in j + 1 .. N - 1) {
      val pj = PCF[j][0]
      val cj = PCF[j][1]
      val fj = PCF[j].subList(2, PCF[j].size).toSet()
      val pi = PCF[i][0]
      val ci = PCF[i][1]
      val fi = PCF[i].subList(2, PCF[i].size).toSet()

      // fiとfjの和集合の数がfjの数を超える場合、上位互換になり得ない
      if (fj.union(fi).size > cj) continue
      if (pi > pj || ci < cj) {
        println("Yes")
        return
      }
    }
  }
  println("No")
}
```

## [C - Reversible](https://atcoder.jp/contests/abc310/tasks/abc310_c)

|[公式解説](https://atcoder.jp/contests/abc310/tasks/abc310_c/editorial)|
|-|

| Difficulty | Solve Prob | Solve Time |
| :---: | :---: | :---: |
| 272 | 95 % | 11 mins |


### Ruby

```ruby:abc310_c.rb
require "set"
N = gets.to_i

set = Set.new
N.times do |i|
  s = gets.chomp
  # 前後反転した文字列と元の文字列を配列で並べ、
  # ソートした後に文字列にする。
  # これにより、"abc"と"cba"を同一とみなせる。
  set << [s, s.reverse].sort.join
end

puts set.size
```

### Kotlin

```kotlin:abc310_c.kt
fun main() {
  val N = readLine()!!.toInt()
  val S = mutableSetOf<String>()

  repeat(N) {
    val s = readLine()!!
    // 前後反転した文字列と元の文字列を配列で並べ、
    // ソートした後に文字列にする。
    // これにより、"abc"と"cba"を同一とみなせる。
    S.add(listOf(s, s.reversed()).sorted().joinToString(""))
  }
  println(S.size)
}
```

## [D - Peaceful Teams](https://atcoder.jp/contests/abc310/tasks/abc310_d)

|[公式解説](https://atcoder.jp/contests/abc310/tasks/abc310_d/editorial)|
|-|

:::note info
深さ優先探索（DFS)
:::

| Difficulty | Solve Prob | Solve Time |
| :---: | :---: | :---: |
| 1368 | 11 % | 38 mins |


### Ruby

```ruby:abc310_d.rb
N, T, M = gets.split.map(&:to_i)
HATE = Array.new(N + 1) { [] }

M.times do
  a, b = gets.split.map(&:to_i).map(&:pred)
  HATE[a] << b
  HATE[b] << a
end

# i 番目の選手(0 <= i < N)
# teamsは各チームの配列の配列
def dfs(i, teams)
  if i == N
    # チーム数がTとなっていた場合条件を満たすためカウント
    return teams.size == T ? 1 : 0
  end
  cnt = 0

  # 既存チームにi番目の選手を追加する場合
  teams.each_with_index do |t, j|
    # tの選手の中にi番目の選手と相性が悪い選手がいた場合は除外
    next if (t & HATE[i]).size > 0
    teams_copy = teams.map { _1.clone }
    teams_copy[j] << i
    cnt += dfs(i + 1, teams_copy)
  end

  # 新たなチームを作りi番目の選手を追加する場合
  cnt += dfs(i + 1, teams + [[i]]) if teams.size < T
  cnt
end

puts dfs(1, [[0]])
```

### Kotlin

```kotlin:abc310_d.kt
fun main() {
  // kotlinでは再帰DFSはすぐにスタックオーバーフローするので記述
  // この問題ではこの方法を使用しなくてもACできる
  Thread(null, ::solve, "solve", 1.shl(26)).start()
}

fun solve() {
  val (N, T, M) = readLine()!!.split(" ").map(String::toInt)
  val HATE = MutableList(N) { mutableListOf<Int>() }
  repeat(M) {
    val (a, b) = readLine()!!.split(" ").map(String::toInt)
    HATE[a - 1].add(b - 1)
    HATE[b - 1].add(a - 1)
  }

  /**
   * i 選手の番号(0 <= i < N)
   * teams チームの配列の配列
   * 場合の数
   */
  fun dfs(i: Int, teams: MutableList<MutableList<Int>>): Int {
    if (i == N) {
      // チーム数がTとなっていた場合条件を満たすためカウント
      return if (teams.size == T) 1 else 0
    }
    var cnt = 0

    // 既存チームにi番目の選手を追加する場合
    teams.forEachIndexed { j, team ->
      // teamの選手の中にi番目の選手と相性が悪い選手がいた場合は早期リターン
      if ((team.intersect(HATE[i])).size > 0) return@forEachIndexed
      val teamsCopy = teams.map { it.toMutableList() }.toMutableList()
      teamsCopy[j].add(i)
      cnt += dfs(i + 1, teamsCopy)
    }

    // 新たなチームを作りi番目の選手を追加する場合
    if (teams.size < T) cnt += dfs(i + 1, teams + mutableListOf(mutableListOf(i)))

    return cnt
  }

  println(dfs(1, mutableListOf(mutableListOf(0))))
}
```

## [E - NAND repeatedly](https://atcoder.jp/contests/abc310/tasks/abc310_e)

|[公式解説](https://atcoder.jp/contests/abc310/tasks/abc310_e/editorial)|
|-|

| Difficulty | Solve Prob | Solve Time |
| :---: | :---: | :---: |
| 1261 | 16 % | 37 mins |

### Ruby

```ruby:abc310_e.rb
N = gets.to_i
S = gets.chomp.chars.map(&:to_i)

# f(0, j) ... f(j - 1, j)の中で、
# zero = fが0である場合の数
# one = fが1である場合の数 = f(0, j) + ... + f(j - 1, j)
ans = zero = one = 0

S.each do |i|
  if i.zero?
    # zeroとなるのは、f(i, i) = 0 ⊼ 0 の場合
    # oneとなるのは、0 ⊼ 0 と 1 ⊼ 0 の場合
    zero, one = 1, zero + one
  else
    # zeroとなるのは、1 ⊼ 1 の場合
    # oneとなるのは、0 ⊼ 1 と f(i, i) の場合
    zero, one = one, zero + 1
  end
  ans += one
end

puts ans
```

### Kotlin

:::note warn
答えは$10^9$を超えるためLong型
:::

```kotlin:abc310_e.kt
fun main() {
  val N = readLine()!!.toInt()
  val S = readLine()!!.toList()

  var ans = 0L
  // f(0, j) ... f(j - 1, j)の中で、
  // zero = fが0である場合の数
  // one = fが1である場合の数 = f(0, j) + ... + f(j - 1, j)
  var zeroOne = Pair(0L, 0L)

  S.forEach {
    if (it == '0') {
      // zeroとなるのは、f(i, i) = 0 ⊼ 0 の場合
      // oneとなるのは、0 ⊼ 0 と 1 ⊼ 0 の場合
      zeroOne = Pair(1L, zeroOne.first + zeroOne.second)
    } else {
      // zeroとなるのは、1 ⊼ 1 の場合
      // oneとなるのは、0 ⊼ 1 と f(i, i) の場合
      zeroOne = Pair(zeroOne.second, zeroOne.first + 1L)
    }
    ans += zeroOne.second
  }
  println(ans)
}
```


# その他のAtCoder関連の解法コード

https://github.com/fumtas1k/atcoder_typical90

https://github.com/fumtas1k/kyopro-tessoku

https://github.com/fumtas1k/atcoder_selected_100

# 参考

https://kenkoooo.com/atcoder