726 字
4 分钟
Beautiful-Numbers

题面#

Let’s define F(x)F(x) as the sum of the digits of xx. An integer xx is considered beautiful if F(F(x))=F(x)F(F(x)) = F(x).

You are given an integer xx. In one move, you can choose any digit in the number and replace it with another. The resulting number cannot have leading zeros.

Your task is to calculate the minimum number of moves (possibly zero) required to make the given number beautiful.

Input

The first line contains a single integer tt (1t1041 \le t \le 10^4) — the number of test cases.

The only line of each test case contains a single integer xx (1x10181 \le x \le 10^{18}).

Output

For each test case, print a single integer — the minimum number of moves (possibly zero) required to make the given number beautiful.

思路#

先分析题意:

yy 的十进制位数为 kk

k2k\ge 2,则 y10k1y \ge 10^{k-1},数位和最多是 9k9k

因此有 F(y)9k<10k1yF(y) \le 9k < 10^{k-1} \le y,从而当 y10y\ge 10 时一定有 F(y)<yF(y) < y

这说明方程 F(y)=yF(y)=y 只能在 yy 为一位数时成立,也就是 y[0,9]y \in [0,9]

因此 F(F(x))=F(x)F(F(x)) = F(x) 等价于 F(x)F(x) 本身是一位数,即 F(x)9F(x) \le 9 于是题目变成把 x 的数位和变到不超过 9,并且操作次数最少

那么,

设原数位和 S=F(x)S = F(x)S9S \le 9xx 已经漂亮,答案为 0 若 S>9S > 9,至少需要把数位和减少 need=S9need = S - 9

每次操作的最大收益#

一次操作只改一位数字,为了让步数尽量少,我们只考虑把某位改小,因为改大只会让数位和更大,需要额外操作再降回来

把某一位从原数字 dd 改成更小的数字,相当于让数位和减少一定的量,而且这个减少量有上限

  • 对于非最高位,可以改成 00,因此这一位最多能让数位和减少 dd

  • 对于最高位,不能改成 00,否则出现前导零,最小只能改成 11,因此这一位最多能让数位和减少 d1d-1

那么:把每一位的这个上限记为 capcap,最高位 cap=d1cap=d-1,其余位 cap=dcap=d

之后,我们使用贪心来选择最少次数:

我们要用尽量少的位,使 capcap 之和至少达到 needneed

因为每次操作的代价都相同,用 kk 次操作能获得的总减少量最多就是最大的 kkcapcap 的和

因此只需要把所有 capcap 从大到小排序,依次取最大的去抵消 needneed,直到 need0need \le 0

取了多少个 cap,就是最少操作次数

代码#

#include <bits/stdc++.h>
using namespace std;
long long F(long long x) {
auto s = to_string(x);
long long result = 0;
for (auto c : s) {
result += c - '0';
}
return result;
}
int main() {
int t;
cin >> t;
while (t --) {
long long x;
cin >> x;
long long sum = F(x);
if (sum <= 9) {
cout << 0 << '\n';
continue;
}
int need = static_cast<int>(sum - 9);
string s = to_string(x);
vector<int> caps;
caps.reserve(s.size());
for (int i = 0; i < (int)s.size(); i ++) {
int d = s[i] - '0';
caps.push_back(i == 0 ? d - 1 : d);
}
sort(caps.rbegin(), caps.rend());
int ans = 0;
for (int cap : caps) {
if (need <= 0) break;
need -= cap;
ans ++;
}
cout << ans << '\n';
}
}
Beautiful-Numbers
https://github.com/posts/beautiful-numbers/
作者
FZSGBall
发布于
2026-05-05
许可协议
CC BY-NC-SA 4.0