Решение
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
data class Person(
var a: Int, // Время на размещение ручной клади (с учётом добавочного времени, если нужно пропустить)
var row: Int, // Номер ряда (смещённый на 180, чтобы удобнее считать)
var pos: Int, // Текущая позиция пассажира в проходе (также "магия" со сдвигом, чтобы упорядочить)
var seated: Boolean = false // Флаг, что пассажир уже сел
)
fun main() {
val reader = BufferedReader(InputStreamReader(System.`in`))
val writer = BufferedWriter(OutputStreamWriter(System.out))
val n = reader.readLine().toInt()
val persons = ArrayList<Person>(n)
// Для учёта занятых мест в каждом ряду (нужно, чтобы понять, сколько человек нужно пропустить).
// Ключ: номер ряда (1..30). Значение: множество занятых мест в этом ряду (A..F).
val occupiedSeatsInRow = mutableMapOf<Int, MutableSet<Char>>()
// Функция для получения количества людей, которых придётся "попросить выйти"
// с учётом уже занятых мест. Возвращает 0, 1 или 2.
fun countNeighborsToStandUp(row: Int, seat: Char): Int {
val occupied = occupiedSeatsInRow.getOrPut(row) { mutableSetOf() }
return when (seat) {
'A' -> {
var cnt = 0
if ('B' in occupied) cnt++
if ('C' in occupied) cnt++
cnt
}
'B' -> if ('C' in occupied) 1 else 0
'C' -> 0
'D' -> 0
'E' -> if ('D' in occupied) 1 else 0
'F' -> {
var cnt = 0
if ('D' in occupied) cnt++
if ('E' in occupied) cnt++
cnt
}
else -> 0
}
}
repeat(n) { i ->
val line = reader.readLine().trim().split(" ")
val aInput = line[0].toInt()
val seatString = line[1]
// seatString имеет формат вида "12A", "1B", "30F" и т.д.
// Нужно отделить номер ряда (числовую часть) от буквы.
val rowPart = seatString.substring(0, seatString.length - 1)
val seatPart = seatString.last() // одна из A..F
val row = rowPart.toInt()
// Считаем, сколько людей нужно пропустить, исходя из уже занятых мест
val k = countNeighborsToStandUp(row, seatPart)
// Добавим 5 или 15 к aInput
val aTime = when (k) {
1 -> aInput + 5
2 -> aInput + 15
else -> aInput
}
// Помечаем место в данном ряду как занятое
occupiedSeatsInRow[row]!!.add(seatPart)
// "Магические" сдвиги, как в C++ коде:
// - row + 180, чтобы у более дальних рядов получалось большее значение
// - pos = 180 - i, чтобы первый по порядку введённый в данных оказался в конце списка (последним в проходе)
// Потом мы развернём список, чтобы идти от тех, кто первым зашёл на борт, к тем, кто зашёл последним.
persons.add(Person(aTime, row + 180, 180 - i, false))
}
// Разворачиваем, чтобы первый пассажир (по входным данным) оказался в голове очереди.
persons.reverse()
var time = 0
// Пока есть хоть один пассажир, который не сел.
var currentList = persons
while (currentList.isNotEmpty()) {
time++
val newList = ArrayList<Person>(currentList.size)
val size = currentList.size
// Идём с хвоста к голове, чтобы при необходимости "проталкивать" пассажиров вперёд
// (аналог цикла for (i = n-1; i >= 0; --i) в C++).
for (i in size - 1 downTo 0) {
val p = currentList[i]
// Если пассажир достиг своего ряда:
if (p.pos == p.row) {
// Если он уже "достал ручную кладь" (a == 0), то он садится (seated = true).
if (p.a == 0) {
p.seated = true
// seated-пассажира не надо класть в newList: он больше не блокирует проход
} else {
// Иначе уменьшаем время на 1, пока он укладывает багаж, и он остаётся в проходе
p.a--
newList.add(p)
}
} else {
// Если пассажир ещё не дошёл до своего ряда, проверяем, может ли он сделать шаг вперёд:
// 1) он — последний в списке (i == size-1), тогда перед ним нет никого
// 2) либо следующего в списке (i+1) нет в том месте, куда мы хотим ступить
// (то есть currentList[i].pos+1 != currentList[i+1].pos) или
// он уже seated (тогда проход свободен для нас).
val canMoveForward = when {
i == size - 1 -> true
else -> {
val nextP = currentList[i + 1]
(p.pos + 1 != nextP.pos) || nextP.seated
}
}
if (canMoveForward) {
p.pos++
}
newList.add(p)
}
}
// Теперь перевернём newList, чтобы снова в начале списка был "первый" пассажир по логике прохода.
newList.reverse()
// Фильтруем всех, кто seated, – они уже выбывают из прохода, но обратите внимание:
// Здесь удобно сначала собрать всех (кроме тех, кто не попал, потому что seated),
// а потом отсеять seated-пассажиров.
val filtered = newList.filter { !it.seated }
currentList = ArrayList(filtered)
}
// Вычитаем 1, так как в конце цикла мы ещё раз сделали time++
writer.write("${time - 1}\\n")
writer.flush()
reader.close()
writer.close()
}