[R31C]交换小球
- 难度 提高
- 时限 1s
- 空限 512m
- 模拟
,,,。 时间限制 1S,内存限制 512M。
思路
个球排成圆环,位置 上初始放着写有数字 的球。每次操作给出 ,要交换「写着 的球」和「写着 的球」所在的位置。最后从写着 的球开始,顺时针输出一圈。
直接模拟「每个位置上放着哪个数字」需要先按值查找位置,单次操作 ,不可接受。换个视角,维护反向映射:
初始时 。每次操作给出值 ,它们所在的位置就是 ,只要交换 与 即可,单次 。
所有操作结束后,再由 反推 :对每个 ,令 。
最后输出时从位置 开始顺时针走一圈,即依次输出
实现上用一个偏移量 ,对应位置 ,按空格分隔输出即可。
复杂度
- 时间:,初始化与构造反向映射各 ,每次操作 ,输出 。
- 空间:,两个长度 的数组。
仓颉实现
import std.convert.*
import std.env.*
main(): Int64 {
let reader = getStdIn()
let first = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let n = first[0]
let q = first[1]
// pos[v] = 数字 v 当前所在的位置(1-indexed),初始 pos[v] = v
var pos = Array<Int64>(n + 1, { i: Int64 => i })
var k = 0
while (k < q) {
let line = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let a = line[0]
let b = line[1]
let tmp = pos[a]
pos[a] = pos[b]
pos[b] = tmp
k++
}
// 反向映射 val[p] = 位置 p 上的数字
let val = Array<Int64>(n + 1, { _ => 0 })
for (v in 1..=n) {
val[pos[v]] = v
}
// 从位置 pos[1] 开始顺时针输出
let sb = StringBuilder()
let start = pos[1]
var firstOut = true
for (i in 0..n) {
let p = ((start - 1 + i) % n) + 1
if (firstOut) {
firstOut = false
} else {
sb.append(" ")
}
sb.append(val[p])
}
println(sb.toString())
return 0
}