[R74E] 三角形具有稳定性
数据规模:,,,所有测试用例中 的总和不超过 。
思路
不稳定度只与所选三根木棒的强度最大值、最小值有关,因此先按强度 升序排列所有木棒,这样任意一次合法选择对应的就是排序后的一段连续区间:设所选三根木棒在排序后位于下标 ,其不稳定度恰为 。
记 为最小的 ,使得区间 内存在三根木棒能围成非退化三角形(不存在则记为正无穷)。那么
一方面, 内某个合法选择的不稳定度不超过 ,所以答案不超过右端;另一方面,取全局最优选择 ,由于 内已存在合法选择,必有 ,于是 ,即答案不小于右端。两边夹逼说明二者相等。
单调不降:若 ,则 内无合法选择,而 ,因此 内也无合法选择,故 。于是可以用双指针维护一个滑动窗口, 只增不减,通过不断右移 找到当前的 。
还剩两个问题:如何判断一个窗口内是否存在合法选择,以及窗口究竟能有多大。
判断合法选择:把窗口内的长度升序排序。若存在相邻三元组 ,显然就有合法选择;反之若所有相邻三元组都不满足,则序列满足 ,归纳可知对任意 都有 ,于是任意三元组(取最小的两个与最大的一个)都无法围成三角形。所以只需检查排序后相邻的三元组。
窗口上界:若窗口内不存在合法选择,排序后有 ,且 ,故 (斐波那契数列)。而 ,矛盾。因此任意 根木棒中必能围出非退化三角形,窗口大小恒不超过 (更精确地说,):若 ,则 已有 根木棒、必含合法选择,与 的最小性矛盾)。
于是只需维护窗口内一个长度不超过 的有序数组,插入、删除与判断各花费 ; 单调右移,总移动量 。
复杂度
时间 (主要是按强度排序),空间 。
仓颉实现
查看仓颉实现
import std.env.*
import std.convert.*
import std.sort.*
let reader = getStdIn()
func insertSorted(buf: Array<Int64>, sz: Int64, v: Int64): Int64 {
var p = sz - 1
while (p >= 0 && buf[p] > v) {
buf[p + 1] = buf[p]
p -= 1
}
buf[p + 1] = v
return sz + 1
}
func removeSorted(buf: Array<Int64>, sz: Int64, v: Int64): Int64 {
var p = 0
while (buf[p] != v) {
p += 1
}
while (p + 1 < sz) {
buf[p] = buf[p + 1]
p += 1
}
return sz - 1
}
func hasTriangle(buf: Array<Int64>, sz: Int64): Bool {
if (sz >= 45) {
return true
}
var t = 2
while (t < sz) {
if (buf[t - 2] + buf[t - 1] > buf[t]) {
return true
}
t += 1
}
return false
}
func solve(): Unit {
let n = Int64.parse(reader.readln().getOrThrow())
let ls = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let sa = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let idx = Array<Int64>(n, { i => i })
sort(idx, lessThan: { x: Int64, y: Int64 => sa[x] < sa[y] })
let l = Array<Int64>(n, { i => ls[idx[i]] })
let a = Array<Int64>(n, { i => sa[idx[i]] })
let buf = Array<Int64>(64, { _ => 0 })
var sz = 0
var i = 0
var j = -1
var ans = Int64.Max
while (i < n) {
if (j < i) {
j += 1
sz = insertSorted(buf, sz, l[j])
}
while (j + 1 < n && !hasTriangle(buf, sz)) {
j += 1
sz = insertSorted(buf, sz, l[j])
}
if (hasTriangle(buf, sz)) {
let d = a[j] - a[i]
if (d < ans) {
ans = d
}
}
sz = removeSorted(buf, sz, l[i])
i += 1
}
if (ans == Int64.Max) {
println("-1")
} else {
println(ans)
}
}
main() {
let t = Int64.parse(reader.readln().getOrThrow())
for (_ in 0..t) {
solve()
}
}