Advertisement
nachtvaohal

packed-prefix

Apr 16th, 2024
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 4.74 KB | None | 0 0
  1. import java.util.Stack
  2.  
  3. /**
  4.  * https://contest.yandex.ru/contest/26133/run-report/112160601/
  5.  *
  6.  * ПРИНЦИП РАБОТЫ
  7.  * Каждая запакованная строка распаковывается и добавляется в экземпляр класса [LongestCommonPrefix]. Сначала формируется
  8.  * числовой коэффициент (число повторений запакованной части строки), далее извлекается запакованная часть.
  9.  *
  10.  * ДОКАЗАТЕЛЬСТВО КОРРЕКТНОСТИ
  11.  * В процессе распаковки контролируется длина распакованной части слова - если она превышает строку, которая хранится в [LongestCommonPrefix]
  12.  * то дальнейшая распаковка не имеет смысла, т.к. НОП не может превышать длины самой короткой строки.
  13.  *
  14.  * ВРЕМЕННАЯ СЛОЖНОСТЬ
  15.  * Сложность распаковки в среднем составит O (n * m), где n - количество строк, m - средняя длина строки
  16.  * Сложность добавления слова в префикс составит O (n), где n - длина существующего префикса.
  17.  *
  18.  * ПРОСТРАНСТВЕННАЯ СЛОЖНОСТЬ
  19.  * Составит O (n), где n - длина наибольшей строки.
  20.  */
  21. fun packedPrefix(packedStrings: List<String>): String {
  22.     val longestCommonPrefix = LongestCommonPrefix()
  23.     for (packed in packedStrings) {
  24.         packed.unpackTo(longestCommonPrefix)
  25.     }
  26.     return longestCommonPrefix.get()
  27. }
  28.  
  29. private fun String.unpackTo(longestCommonPrefix: LongestCommonPrefix) {
  30.     var multiplier = 1
  31.     var i = 0
  32.     var prefixIndex = 0
  33.     val stack = Stack<Packed>()
  34.     while (i < this.length) {
  35.         val currentChar = this[i]
  36.         when {
  37.             currentChar.isDigit() -> {
  38.                 multiplier = currentChar.digitToInt()
  39.             }
  40.             currentChar == '[' -> {
  41.                 stack.push(Packed(multiplier, StringBuilder()))
  42.             }
  43.             currentChar == ']' -> {
  44.                 val unpackedPart = stack.pop().multipliedPart
  45.                 if (stack.isNotEmpty()) {
  46.                     stack.peek().part.append(unpackedPart)
  47.                 } else {
  48.                     // закончилась запакованная часть, посимвольно добавляем к результату
  49.                     for (char in unpackedPart) {
  50.                         if (!longestCommonPrefix.add(char, prefixIndex++)) {
  51.                             return
  52.                         }
  53.                     }
  54.                 }
  55.             }
  56.             // is letter
  57.             else -> {
  58.                 if (stack.isNotEmpty()) {
  59.                     stack.peek().part.append(currentChar)
  60.                 } else {
  61.                     // идём по строке без множителя
  62.                     if (!longestCommonPrefix.add(currentChar, prefixIndex++)) {
  63.                         return
  64.                     }
  65.                 }
  66.             }
  67.         }
  68.         i++
  69.     }
  70.     longestCommonPrefix.setCompleted()
  71. }
  72.  
  73. private class LongestCommonPrefix {
  74.     private val result = StringBuilder()
  75.     private var completed = false
  76.  
  77.     fun add(char: Char, index: Int): Boolean {
  78.         return when {
  79.             // удлинение строящегося префикса
  80.             ! completed && index == result.length -> {
  81.                 result.append(char)
  82.                 true
  83.             }
  84.             // проверка совпадения с существующим префиксом
  85.             completed && index < result.length && char == result[index] -> {
  86.                 true
  87.             }
  88.             else -> {
  89.                 result.setLength(index)
  90.                 false
  91.             }
  92.         }
  93.     }
  94.  
  95.     fun get(): String {
  96.         return result.toString()
  97.     }
  98.  
  99.     fun setCompleted() {
  100.         completed = true
  101.     }
  102. }
  103.  
  104. private data class Packed(
  105.     val multiplier: Int,
  106.     val part: StringBuilder
  107. ) {
  108.     val multipliedPart: String
  109.         get() {
  110.             val unpackedPart = StringBuilder()
  111.             repeat(multiplier) {
  112.                 unpackedPart.append(part)
  113.             }
  114.             return unpackedPart.toString()
  115.         }
  116. }
  117.  
  118. fun main() {
  119.     val reader = System.`in`.bufferedReader()
  120.     val packedStringCount = reader.readLine().toInt()
  121.     val packedStrings = List(packedStringCount) {
  122.         reader.readLine()
  123.     }
  124.  
  125.     println(packedPrefix(packedStrings))
  126. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement