[R4D] 排队问题

  • 难度 入门
  • 时限 1s
  • 空限 512m
  • 排序前缀和

思路

nn 名同学都问问题时,按 aia_i 从小到大排队可使等待时间总和最小。设按该顺序第 jj 名同学(00 开始编号)前面的同学的所需时间之和为 wait[j]wait[j],全部同学的总等待时间为 total=wait[j]total = \sum wait[j]

若去掉排在第 jj 名的同学 ii:他的等待时间 wait[j]wait[j] 被减去;排在他后面的 n1jn-1-j 名同学每人等待时间都减少 aia_i。因此答案为

totalwait[j]ai×(n1j)total - wait[j] - a_i \times (n-1-j)

所需时间相同的同学互换位置不影响上式结果,所以按值排序后任意同名次的同学直接套用公式即可。

复杂度:时间 O(nlogn)O(n \log n),空间 O(n)O(n)

仓颉实现

import std.convert.*
import std.env.*
import std.sort.*

func solve() {
    let reader = getStdIn()
    let n = Int64.parse(reader.readln().getOrThrow())
    let nn = n
    let a = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p => Int64.parse(p) })
    let order = Array<Int64>(nn, { i => i })
    sort(order, key: { i => a[i] })
    let pos = Array<Int64>(nn, { _ => 0 })
    let wait = Array<Int64>(nn, { _ => 0 })
    var pre: Int64 = 0
    for (j in 0..nn) {
        pos[order[j]] = j
        wait[j] = pre
        pre += a[order[j]]
    }
    var total: Int64 = 0
    for (j in 0..nn) {
        total += wait[j]
    }
    let sb = StringBuilder()
    for (i in 0..nn) {
        let j = pos[i]
        sb.append(total - wait[j] - a[i] * (n - 1 - j))
        sb.append("\n")
    }
    print(sb.toString())
}

main() {
    solve()
}