[R50D]三元组2
题目
给定三个数组 (长度分别为 )和非负整数 。求满足 且 的三元组 的个数。
对于 的数据,,,。
思路
先把 分别升序排序,元素的相对顺序不影响计数。
两个条件可以改写为:固定一对 满足 ,则合法的 需要同时满足
即 。这要求 ,也就是 ;再加上 ,得到 。
于是答案可以按 拆分:
对固定的 ,记 ,(这是关于 的常量),并把 预处理出来。则内层求和为
其中 ,。对 做前缀和 后,区间和 可 取得。
,对每个 二分一次即可。
复杂度
- 时间:排序 ,预处理 各 与 ,枚举 每次 ,总计 。
- 空间:。
- 答案最大可达 ,需用 64 位整数。
仓颉实现
import std.env.*
import std.convert.*
import std.sort.*
// lower_bound: 第一个 >= key 的下标,不存在返回 n
func lowerBound(a: Array<Int64>, key: Int64): Int64 {
var lo: Int64 = 0
var hi: Int64 = Int64(a.size)
while (lo < hi) {
let mid = (lo + hi) / 2
if (a[mid] < key) {
lo = mid + 1
} else {
hi = mid
}
}
return lo
}
// upper_bound: 第一个 > key 的下标,不存在返回 n
func upperBound(a: Array<Int64>, key: Int64): Int64 {
var lo: Int64 = 0
var hi: Int64 = Int64(a.size)
while (lo < hi) {
let mid = (lo + hi) / 2
if (a[mid] <= key) {
lo = mid + 1
} else {
hi = mid
}
}
return lo
}
main(): Int64 {
let reader = getStdIn()
let firstLine = reader.readln().getOrThrow().split(" ", removeEmpty: true)
let na = Int64.parse(firstLine[0])
let nb = Int64.parse(firstLine[1])
let nc = Int64.parse(firstLine[2])
let d = Int64.parse(firstLine[3])
let a = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ s: String => Int64.parse(s) })
let b = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ s: String => Int64.parse(s) })
let c = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ s: String => Int64.parse(s) })
sort(a)
sort(b)
sort(c)
// h[j] = countA(<= b[j])
let nbInt = nb
let h = Array<Int64>(nbInt, { _ => 0 })
for (j in 0..nbInt) {
h[j] = upperBound(a, b[j])
}
// H[i] = h[0]+...+h[i-1]
let H = Array<Int64>(nbInt + 1, { _ => 0 })
for (j in 0..nbInt) {
H[j + 1] = H[j] + h[j]
}
var ans: Int64 = 0
let ncInt = nc
for (k in 0..ncInt) {
let ck = c[k]
let lo = ck - d
let jl = lowerBound(b, lo)
let jr = upperBound(b, ck) - 1
if (jl > jr) {
continue
}
let base = lowerBound(a, lo)
let cnt = jr - jl + 1
ans += (H[jr + 1] - H[jl]) - base * cnt
}
println(ans.toString())
return 0
}