Решение
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import kotlin.math.min
fun main() {
val reader = BufferedReader(InputStreamReader(System.`in`))
val writer = BufferedWriter(OutputStreamWriter(System.out))
// Считываем N
val N = reader.readLine().toInt()
// Считываем стоимости обедов по дням в массив costs (1-based проще для понимания, но можно и 0-based)
val costs = IntArray(N + 1)
for (i in 1..N) {
costs[i] = reader.readLine().toInt()
}
// Если N == 0, то ответ тривиален: суммарная стоимость = 0, купоны 0 и 0
if (N == 0) {
writer.write("0\\n")
writer.write("0 0\\n")
writer.close()
return
}
// dp[i][k] = минимальная стоимость за первые i дней, если после i-го дня осталось k купонов
// Инициализируем "бесконечностью" (здесь возьмём достаточно большое число)
val INF = 10_000_000
val dp = Array(N + 1) { IntArray(N + 1) { INF } }
// Для восстановления ответа
// prev[i][k] будет хранить пару (k_old, usedCoupon),
// где usedCoupon = false/true (false = платили день i, true = использовали купон в день i)
val prev = Array(N + 1) { Array<Pair<Int, Boolean>?>(N + 1) { null } }
dp[0][0] = 0 // в начале 0 дней, 0 купонов, 0 рублей
// Заполняем DP
for (day in 1..N) {
for (kOld in 0..N) {
val oldCost = dp[day - 1][kOld]
if (oldCost == INF) continue // Невозможное состояние, пропускаем
// 1) ПЛАТИМ за обед
val costPay = oldCost + costs[day]
val kNewPay = if (costs[day] > 100) kOld + 1 else kOld
if (kNewPay <= N && costPay < dp[day][kNewPay]) {
dp[day][kNewPay] = costPay
prev[day][kNewPay] = Pair(kOld, false)
}
// 2) ИСПОЛЬЗУЕМ купон (если есть)
if (kOld > 0) {
val costUseCoupon = oldCost // бесплатно
val kNewCoupon = kOld - 1
if (costUseCoupon < dp[day][kNewCoupon]) {
dp[day][kNewCoupon] = costUseCoupon
prev[day][kNewCoupon] = Pair(kOld, true)
}
}
}
}
// Ищем минимальную стоимость среди dp[N][k] и при равенстве - максимальный k
var minCost = INF
var bestK = 0
for (k in 0..N) {
if (dp[N][k] < minCost) {
minCost = dp[N][k]
bestK = k
} else if (dp[N][k] == minCost && k > bestK) {
// При одинаковой стоимости выбираем большее k
bestK = k
}
}
// Восстановим путь (дни использования купонов)
val usedDays = mutableListOf<Int>()
var curK = bestK
var i = N
while (i > 0) {
val (prevK, usedCoupon) = prev[i][curK]!!
if (usedCoupon) {
// Значит в день i использовали купон
usedDays.add(i)
}
// Переходим к предыдущему состоянию
curK = prevK
i--
}
usedDays.reverse() // чтобы вывести в порядке возрастания дня
// Количество использованных купонов:
val K2 = usedDays.size
// Количество оставшихся купонов:
val K1 = bestK
// Вывод результатов:
writer.write("$minCost\\n")
writer.write("$K1 $K2\\n")
for (day in usedDays) {
writer.write("$day\\n")
}
writer.close()
}