【构造】【P9215】扶苏与 1

· · 题解

【构造】【P9215】扶苏与 1

Description

给出一个数字串 x,求一个长度不超过 x 长度的数字串 y,使得 x + y 的竖式计算有恰好 k 个进位,或报告无解。

## Analysis 接下来我们称 $x$ 的最高位是第 $1$ 位,最低位是第 $n$ 位。『第 $i$ 位』指的是从左到右数第 $i$ 个位置。 首先能观察到一个简单的事实:如果第 $k$ 位不为 $0$,那么可以简单地构造一个前 $k$ 位是 $9$、后 $n - k$ 位是 $0$ 的数字 $y$ 来做到恰好 $k$ 个进位。例如,若 $x = 10101$,$k = 3$,那么构造 $y = 99900$ 可以在第 $1,2,3$ 位上构造出进位。 **证明**: 首先第 $k$ 位之后都是 $0$,这些位置不会有进位。 $x$ 的第 $k$ 位不为 $0$,加上 $9$ 一定会有 $1$ 的进位; 假设第 $i$ 位($1 < i \leq k$)产生了 $1$ 的进位,考虑 $y$ 的第 $i$ 位是 $9$,加上进上来的 $1$,再加上 $x$ 对应位的原数,得数一定不小于 $10$,所以一定会产生 $1$ 的进位。 根据归纳假设,第 $1 \sim k$ 位都会产生进位,$k + 1\sim n$ 位没有进位,得证。 接下来考虑第 $k$ 位为 $0$ 时应该如何构造: 找到第 $k$ 位之前最后一个不为 $0$ 的位置 $p$(显然存在),然后根据上面的方法我们可以构造 $p$ 个进位。考虑构造剩下的 $k - p$ 个进位。 找到第 $k$ 位之后第一个不为 $0$ 的位置 $q$。如果这样的 $q$ 不存在,说明我们不能构造更多的进位,此时显然无解。 如果 $q$ 存在,我们来证明 $[p + 1, q - 1]$ 这段区间(显然这段区间里全部都是 $0$)的长度不小于 $k - p$。: 这段区间的长度是 $q - 1 - (p + 1) + 1 = q - p - 1$。因为 $q > k$,所以 $q - p > k - p$。所以 $q - p - 1 \geq k - p$。 我们从第 $q$ 位起,向前填充 $k - p$ 个 $9$。也就是给 $[q - (k - p) + 1, q]$ 这段区间填充上 $9$。且给 $q - (k - p)$ 这个位置填充上 $0$。我们来证明这样构造出了 $k - p$ 个进位: 因为 $x$ 第 $q$ 位不为 $0$,加上 $9$ 一定不小于 $10$,产生了一个进位。再用与前面类似的归纳,假设下一位产生了进位,那么加上 $y$ 这一位的 $9$,一定有进位。因为一共有 $k - p$ 个 $9$,所以一共构造出来了 $k - p$ 个进位。特别的,$q - (k - p) = p + (q - k) \geq p + 1 \in [p + 1, q - 1]$,所以 $x$ 第 $q - (k - p)$ 位也是 $0$,$y$ 的这一位也是 $0$,加上第 $q - (k - p) + 1$ 位的进位也不会有新的进位。所以我们恰好构造了 $k - p$ 个进位。 这样,我们在 $[1, p]$ 区间上构造了 $p$ 个进位,$[q - (k - p) + 1, q]$ 区间上构造了 $k - p$ 个进位。一共构造出了 $k$ 个进位。其他位置上全填充 $0$,不会产生新的进位。 以下两张图分别是 $k = 5$ 和 $k = 8$ 的例子,可以结合图片来理解构造方法。 ![](https://cdn.luogu.com.cn/upload/image_hosting/m54hwvxo.png) ![](https://cdn.luogu.com.cn/upload/image_hosting/ltnr0l6l.png) ## Code 在实现上,因为字符串下标是从 $0$ 开始的,所以一些位置有减去 $1$ 的操作。 ```cpp #include <assert.h> #include <string> #include <iostream> #include <algorithm> int T; int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); for (std::cin >> T; T; --T) { int k; std::string s; std::cin >> s >> k; if (s == "0") { std::cout << "-1\n"; continue; } std::string ans; assert(k <= s.length()); int endp = k - 1; while (s[endp] == '0') --endp; for (int i = 0; i <= endp; ++i) { ans.push_back('9'); } if (endp != k - 1) { int q = k - 1; while (q < s.size() && s[q] == '0') ++q; if (q == s.size()) { std::cout << "-1\n"; continue; } int p = k - endp - 1; p = q - p + 1; for (int i = endp + 1; i < p; ++i) ans.push_back('0'); for (int i = p; i <= q; ++i) ans.push_back('9'); } while(s.size() > ans.size()) ans.push_back('0'); std::cout << ans << '\n'; } } ```