[R58D] 双胞胎周长
- 难度 普及+/提高
- 时限 1s
- 空限 512m
- 数学计数
数据规模:,,所有 模 同余。
思路
设 为周长为 的整数边长三角形个数:三边无序,,,。
无序三元组计数:先数允许退化的三元组,即 拆成恰好三个正整数的无序拆分,方案数为
退化计数:退化()等价于 ;此时 ,故 自动满足,无需额外约束。于是退化三元组与二元组「,」一一对应,其中 :固定 时 可取 共 个,求和得
因此 可 算出, 在 Int64 范围内;该公式对任意周长成立,与「全部元素模 同余」的约定无关。
统计答案:把每个 都算出来, 相同的下标两两成对。将 值排序后扫描连续相等段,段长为 时贡献 。
复杂度:时间 ,空间 。
仓颉实现
import std.env.*
import std.convert.*
import std.sort.*
// 周长为 p 的整数边长三角形个数:
// 把 p 拆成三个正整数(无序)的方案数 P = floor((p^2+3)/12),
// 其中退化的(x+y <= z)有 D 个:m = floor(p/2),m=2k 时 D=k^2,m=2k+1 时 D=k(k+1)。
func triangles(p: Int64): Int64 {
let P = (p * p + 3) / 12
let m = p / 2
let k = m / 2
let d = if (m % 2 == 0) { k * k } else { k * (k + 1) }
return P - d
}
main(): Int64 {
let reader = getStdIn()
let n = Int64.parse(reader.readln().getOrThrow())
let a = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
var ss = Array<Int64>(a.size, { _ => 0 })
for (i in 0..a.size) {
ss[i] = triangles(a[i])
}
sort(ss)
var ans: Int64 = 0
var i: Int64 = 0
while (i < ss.size) {
var j = i
while (j < ss.size && ss[j] == ss[i]) {
j++
}
let c = j - i
ans += c * (c - 1) / 2
i = j
}
println(ans)
return 0
}