Problem:
Problem C: Last One

Problem

あなたは、集合好きな友人Aと一風変わったゲームをしてみる事にした。

n個の要素からなる重複が許される非負の整数の集合Sが与えられる。集合Sに含まれる各要素は非負のpi進数である。集合Sに対して
以下のStep1~3を1つのターンとして、あなたと相手の二人が交互にターンを繰り返す。各ターンではこの番号の順に操作を行う。

Step 1: 集合Sに含まれる全ての要素を一度取り除き、その取り除いた各要素を2進数に変換して、0を消して1が1つ以上連続する部分に分割し、その分割された部分を全て集合Sに加える。

Step 2: このとき集合Sが空になっていたならば、現在このターンをプレイしているプレイヤーは負ける。

Step 3: 集合Sに含まれる要素aを1つ選び、そのaから 1 ≤ x ≤ a を満たす任意の整数xを引く。

下の図は次の入力が与えられたときの最初の1ターンの進行の仕方のうちの1つの例である。

4
10 3
2 11
16 5
16 AE

最初はあなたのターンだ。与えられた入力に対して両者が最善を尽くすとき、果たしてあなたに勝ち目はあるのだろうか。

Input

入力は次の形式で与えられる。

n
p1 m1
p2 m2
...
pi mi
...
pn mn

集合の要素であるpi進数miがn個与えられる。集合の要素の数nは105を超えない。また、2≦pi≦62を満たす。
pi進数miは通常の数字である0~9に加え、アルファベット52文字を使用する。
その順番は012...789ABC...XYZabc...xyzを昇順とし、i番目までの文字を使うものとする。また、pi進数miは10進数で218-1を超えない.

Output

与えられた入力に対しあなたが勝てるならwin、負けるならloseを出力せよ。

Sample Input 1

1
10 1

Sample Output 1

win

Sample Input 2

2
10 1
10 1

Sample Output 2

lose

Sample Input 3

3
25 53AI
43 3BI0
62 pn6

Sample Output 3

win

Solution in Scala (judge verdict: Accepted)

object Main extends App {

  import scala.io.StdIn._
  val n = readInt
  implicit val memo = Array.tabulate(19){_ ⇒ None: Option[Int]}
  implicit val memo2 = Array.tabulate(19){len ⇒ Array.tabulate(len + 1){_ ⇒ None: Option[List[Int]]}}
  val numbers = Array.tabulate(n){_ ⇒
    val arg = readLine.trim.split(' ')
    g(arg.tail.headOption.getOrElse("").asBase(arg.head.toInt), 0)
  }
  if (numbers.foldLeft(0)(_^_) != 0)
    println("win")
  else println("lose")
  def g(number: Int, current: Int): Int = {
    if (number == 0) g(current)
    else if (number % 2 == 1) g(number / 2, current + 1)
    else if (current == 0) g(number / 2, 0)
    else g(current) ^ g(number / 2, 0)
  }
  def g(length: Int)(implicit memo: Array[Option[Int]]): Int = {
    if (length == 0) 0
    else memo(length) match {
      case Some(r) ⇒ r
      case None ⇒
        val nextState = (0 until length).flatMap(max ⇒ separation(length - max - 1, max)(memo2).map(_ ^ g(max))).distinct.sorted
        var find = false
        var prev = -1
        for (n ← nextState if !find) {
          if (prev + 1 != n) find = true
          prev = prev + 1
        }
        if (!find) prev += 1
        memo(length) = Some(prev)
        prev
    }
  }
  def separation(length: Int, max: Int)(implicit memo2: Array[Array[Option[List[Int]]]]): List[Int] = {
    if (length <= 0 || max == 0) List(0)
    else memo2(length)(math.min(length, max)) match {
      case Some(l) ⇒ l
      case None ⇒ (0 to math.min(length, max)).flatMap(nextMax ⇒ separation(length - nextMax - 1, nextMax).map(_ ^ g(nextMax))).toList.distinct.also(l ⇒ memo2(length)(math.min(length, max)) = Some(l))
    }
  }
  implicit class AsPrimeBase(val value: String) extends AnyVal{
    def asBase(base: Int): Int = {
      value.map{
        case c if c.isDigit ⇒ c.asDigit
        case c if c.isUpper ⇒ c - 'A' + 10
        case c ⇒ c - 'a' + 36
      }.foldLeft(0){(a, b) ⇒ a * base + b}
    }
  }
  implicit class Extension[T](val value :T) extends AnyVal {
    @inline
    def let[A](@inline func: T ⇒ A): A = func(value)
    @inline
    def also(@inline func: T ⇒ Unit): T = {func(value); value}
    @inline
    def takeIf(@inline predicate: T ⇒ Boolean): Option[T] = Some(value).filter(predicate)
  }
}