[R73E] 跳跳棋
数据规模:,。
思路
两枚棋子把圆盘分成两段弧。令 ,记 为较短那条弧的长度。一次操作把一枚棋子翻到关于另一枚棋子的对称位置,等价于把这条短弧翻到另一侧:短弧的中点 沿圆移动 (移动方向由操作哪枚棋子决定),同时 、 在弧两端的相对位置互换,即方向翻转。
交换 、 的位置后,两枚棋子仍分居同一条短弧的两端:短弧中点不变,但方向必须翻转。因此操作次数 必须为奇数,且 的净位移是 个 之和,记作 ,必须满足 。由于每一步可自由选择 或 ,任何满足 、 的奇数 都能实现。
的最小正解为 。若 是奇数,连续翻转 恰好 步即可: 的总位移 是 的倍数,中点回到原位,方向翻转奇数次,恰好完成交换,且步数不可能更少;若 是偶数,则 的一切整数解 都是偶数,与 必须为奇数矛盾,此时无解,输出 。
复杂度
每组数据只需一次 ,时间 ,空间 。
仓颉实现
查看仓颉实现
import std.env.*
import std.convert.*
func gcd0(a: Int64, b: Int64): Int64 {
var x = a
var y = b
while (y != 0) {
let t = x % y
x = y
y = t
}
return x
}
func solve(reader: ConsoleReader) {
let mab = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let m = mab[0]
let a = mab[1]
let b = mab[2]
var d = (b - a) % m
if (d < 0) {
d += m
}
var s = d
if (m - d < s) {
s = m - d
}
let g = gcd0(m, s)
let n = m / g
if (n % 2 == 1) {
println(n)
} else {
println("-1")
}
}
main() {
let reader = getStdIn()
let t = Int64.parse(reader.readln().getOrThrow())
for (_ in 0..t) {
solve(reader)
}
}