计算客(problem081)奥特曼打小怪兽

题目: http://nanti.jisuanke.com/t/81

不关心奥特曼和小怪兽的,题目包含以下的信息:

  1. 两组变量a和b,a可以认为是常理,b会因为时间t的增长而贡献更多;

  2. 多组的a和b,只要不在同一个时间点,就可以相加;

  3. a + b * t 和多组相加的结果,排序后,得到的第k个值,就是所需要的答案;

得到以下的解法:

  1. 先将只打一招所扣减的血量,根据时间从1增长,加入一个链表,并排序;这里只需要k个值即可;但考虑到,加入k个值以后,后续的计算有可能会找到更小的值,所以需要多计算一组;

  2. 只要两(组)招不是在同一时刻发的,那么它们就可以组合起来,并将结果加入链表中;排序;

  3. 将得到的链表截断到k,循环第二步,直到不会再更新链表最大的序号为止;

这里链表是按照伤害从大到小的顺序排的,相同的伤害序号一致,所以,最后得到的链表头部的值,就是所要的结果;

import java.util.Scanner

object App extends App {

  val scanner = new Scanner(System.in)

  val n = scanner.nextInt()
  val k = scanner.nextInt()

  val as = Array.fill(n)(0)
  val bs = Array.fill(n)(0)

  for {
    i <- 0 until n
  } {
    as(i) = scanner.nextInt()
    bs(i) = scanner.nextInt()
  }

  case class Node(r: Int, ts: Set[Int], index: Int)

  def fill(nodes: List[Node], r: Int, ts: Set[Int]): List[Node] = {
    val head = nodes.head
    if (r > head.r) {
      Node(r, ts, head.index + 1) :: nodes
    } else if (r == head.r) {
      Node(r, ts, head.index) :: nodes
    } else {
      val list = fill(nodes.tail, r, ts)
      val nHead = list.head
      if (nHead.r == head.r) {
        head.copy(index = nHead.index) :: list
      } else {
        head.copy(index = nHead.index + 1) :: list
      }
    }
  }

  def arrange(nodes: List[Node], i: Int, t: Int): List[Node] = {
    if (i == 0 && nodes.head.index >= k) nodes
    else {
      val a = as(i)
      val b = bs(i)
      val r = a + b * t
      val newNodes = fill(nodes, r, Set(t))
      if (i < n - 1) {
        arrange(newNodes, i + 1, t)
      } else {
        arrange(newNodes, 0, t + 1)
      }
    }
  }

  def compact(nodes: List[Node]): List[Node] = {
    val maxR = nodes.head.r
    def add(nodes: List[Node], result: List[Node]): List[Node] =
      nodes match {
        case List(x) if (x.index == 0) => result
        case head :: tail =>
          var newResult = result
          for {
            node <- tail
            if (node.index > 0 && head.ts.intersect(node.ts).size == 0 && head.r + node.r < maxR)
          } {
            newResult = fill(newResult, head.r + node.r, head.ts ++ node.ts)
          }

          add(tail, newResult)
      }

    val indexA = nodes.head.index

    val result = add(nodes, nodes)

    val indexB = result.head.index

    if (indexA == indexB) {
      nodes
    } else {
      compact(result.dropWhile(_.index > k))
    }
  }

  val nodes = arrange(List(Node(0, Set(), 0)), 0, 1).dropWhile(_.index > k)

  val result = compact(nodes).dropWhile(_.index > k).head

  println(result.r)
}


时间复杂度分析:第一步需要得到至少K个值的链表,这个可以认为是O(K);第二步每次调用需要O(K * K),以及O(K)的链表插入排序,所以复杂度是O(K * K * K); 需要循环的次数,我算不清楚,大概再logK ~ K之间; 所以最坏得情况应该是 O(K * K * K * K); 但这个计算有可能是错的,应该按照K最大50000,那么这个程序应该是跑不完的,如果有兴趣的话,帮我计算一下,不胜感激;



你可能感兴趣的:(scala)