[R49B]减法


数据规模:1k1001 \le k \le 1001x10k11 \le x \le 10^k - 1

思路

10k110^k - 1kk 个 9 组成的数,例如 k=3k = 3 时为 999999。用 9999999\cdots9 减去 xx,等价于求 xx9 的补数:把 xx 左侧补前导零到 kk 位,再让每一位 dd 变成 9d9 - d。例如 999123=876999 - 123 = 876,每位正是 91=89-1=892=79-2=793=69-3=6

注意当 x=10k1x = 10^k - 1(即 kk 个 9)时,每一位补数都是 00,结果为 00;最高位也可能产生前导零,因此最后需要去掉前导零、至少保留一个数字。

由于 kk 最大为 100100,结果可达 1010010^{100} 量级,超出整数范围,全程用字符串 / 字节数组处理即可。

复杂度

时间 O(k)O(k),空间 O(k)O(k)

仓颉实现

import std.env.*
import std.convert.*

main(): Int64 {
    let reader = getStdIn()
    let parts = reader.readln().getOrThrow().split(" ", removeEmpty: true)
    let k = Int64.parse(parts[0])
    let xStr = parts[1]
    let xLen = Int64(xStr.size)
    // 把 x 左补前导 '0' 到 k 位
    let builder = StringBuilder()
    var i = 0
    while (i < k - xLen) {
        builder.append(r'0')
        i++
    }
    builder.append(xStr)
    let padded = builder.toString()
    // 每位做 9 的补数:结果位 = '9' - (c - '0')
    let out = Array<UInt8>(k, { idx: Int64 =>
        let c = padded[idx]
        57u8 - (c - 48u8)
    })
    // 去掉前导零,保留至少一个数字
    var start = 0
    while (start < k - 1 && out[start] == 48u8) {
        start++
    }
    let s = start
    let trimmed = Array<UInt8>(k - s, { idx: Int64 => out[s + idx] })
    println(String.fromUtf8(trimmed))
    return 0
}