[R20E]数对谜题
- 难度 提高
- 时限 1s
- 空限 512m
- 数论
题目
给定两个正整数 和 ,找出所有满足以下条件的有序正整数对 :
- ;
- 。
若有多个解,按 的大小升序输出。多组测试数据。
对于 的数据,,,,且 。
思路
设 ,,,则 。代入两个条件:
记 ,则 必为 的因子,且 。又由 、 可得
即 。
因此只需枚举 的所有因子 ,判断 是否为完全平方数 ;若是,则 ,,得到一组解 ,。
注意两点:
- 必须额外校验 。若 ,则实际有 ,此时 ,不满足条件;
- 每个解唯一对应一个因子 (因为 唯一确定 与 ),所以枚举过程不会产生重复解。
,试除到 即可枚举全部因子;,平方根在 Int64 范围内,完全平方判断可先取浮点平方根再向两侧微调修正(微调次数为常数,结果精确)。
复杂度
- 时间复杂度:,每组数据试除 次, 完全够快。
- 空间复杂度:, 为解的个数,用于收集并排序输出。
仓颉实现
import std.convert.*
import std.env.*
import std.math.*
import std.sort.*
import std.collection.*
func gcd(a: Int64, b: Int64): Int64 {
var x = a
var y = b
while (y != 0) {
let t = x % y
x = y
y = t
}
return x
}
// 若 v 是完全平方数返回其平方根,否则返回 -1
func intSqrtPerfect(v: Int64): Int64 {
var r = Int64(sqrt(Float64(v)))
while (r * r > v) { r -= 1 }
while ((r + 1) * (r + 1) <= v) { r += 1 }
if (r * r == v) { return r }
return -1
}
// 枚举差值 d = a - b(d 必为 X 的因子),检查 (d, s) 是否给出合法解
func tryPair(x: Int64, y: Int64, d: Int64, ans: ArrayList<Array<Int64>>): Unit {
let s = intSqrtPerfect(d * d + 4 * y)
if (s < 0) { return }
let a = (s + d) / 2
let b = (s - d) / 2
if (b <= 0) { return }
if (gcd(a, b) != 1) { return }
let g = x / d
ans.add([g * a, g * b])
}
func solve(reader: ConsoleReader, sb: StringBuilder): Unit {
let parts = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let x = parts[0]
let y = parts[1]
var ans = ArrayList<Array<Int64>>()
var i: Int64 = 1
while (i * i <= x) {
if (x % i == 0) {
tryPair(x, y, i, ans)
let j = x / i
if (j != i) { tryPair(x, y, j, ans) }
}
i += 1
}
sort(ans, key: { p: Array<Int64> => p[0] })
sb.append(ans.size)
sb.append("\n")
for (p in ans) {
sb.append(p[0])
sb.append(" ")
sb.append(p[1])
sb.append("\n")
}
}
main(): Int64 {
let reader = getStdIn()
let t = Int64.parse(reader.readln().getOrThrow())
let sb = StringBuilder()
var i: Int64 = 0
while (i < t) {
solve(reader, sb)
i += 1
}
print(sb.toString())
return 0
}