优美数字:三种C++实现
题目来源:CCF-GESP 2025年9月二级C++。
题目描述
如果一个正整数在十进制下的所有数位都相同,小A认为这个正整数是优美的。例如666、999999。123123123就不优美。小A想知道不超过n的正整数中有多少优美的数字。
输入格式
一行,一个正整数n。
输出格式
一行,一个正整数,表示不超过n的优美正整数的数量。
输入输出样例 #1
输入:
6
输出:
6
输入输出样例 #2
输入:
2025
输出:
28
说明/提示
对于所有测试点,保证1≤n≤2025。
分析与实现
数据范围只有2025,直接枚举1到n也是可以的,但我们可以多想几种写法。
按位数分类直接判断
因为n最大2025,优美数只有1到9(一位数)、11,22,...,99(两位数)、111,222,...,999(三位数),以及1111(四位数)。所以可以针对位数分类统计。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, cnt = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
// 枚举 1 到 n
if (i < 10) { // 一位数,是优美数
cnt++;
} else if (i < 100 && i / 10 == i % 10) { // 两位数且个位与十位相等,是优美数
cnt++;
} else if (i < 1000 && i / 100 == i % 10 && i / 10 % 10 == i % 10) { // 三位数且百位与个位相等且十位与个位相等,是优美数
cnt++;
} else if (i == 1111) { // 四位数只有 1111 是优美数
cnt++;
}
}
cout << cnt;
return 0;
}
这段代码硬编码了位数条件,对于更大的范围就不适用,但针对本题够了。
通用拆位检查
如果需要处理更大的n,我们可以对每个数拆位,判断所有位是否相同。思路是取出个位数字g,然后不断去掉最低位,对比是否都等于g。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, cnt = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
int t = i;
bool flag = true; // 假设 t 为优美数
int g = t % 10; // 个位
while (t > 0) {
if (g != t % 10) { // 任意位不等于个位
flag = false;
break;
}
t /= 10;
}
cnt += flag;
}
cout << cnt;
return 0;
}
这种做法更通用,但每次都要拆位,当n较大时效率较低。
构造优美数再过滤
另一种思路是直接构造所有可能的优美数:由数字d(1~9)构造1位、2位、3位、4位数,判断是否≤n。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, cnt = 0;
cin >> n;
for (int i = 1; i <= 9; i++) { // 枚举组成优美数的数字
int t = 0;
for (int j = 1; j <= 4; j++) { // 枚举 1-4 位
t = t * 10 + i;
if (t <= n) {
cnt++;
}
}
}
cout << cnt;
return 0;
}
这个方法只会遍历到有限的几个优美数,复杂度与n无关,是最优雅的方式。在本题n极小的情况下体现不出优势,但可以推广到更大的范围。
三种写法都能通过题目,实际选择可以根据自己对代码简洁性和通用性的偏好来定。
