题解:学而思编程 拼数字
【题目来源】
学而思编程:拼数字
【题目描述】
小猴喜欢玩数字卡片游戏,每张卡片上的数字都是 \(0∼9\) 中的任意一个。
小猴已经积累了很多的数字卡片,并且 \(0∼9\) 的数字卡片小猴各有 \(n\) 张。
小猴想用这些卡片来拼从 \(1\) 开始的一些连续正整数,他想要知道自己手里的卡片能从 \(1\) 开始最大能拼到多少。
例如,小猴现在 \(0∼9\) 的数字卡片各有 \(3\) 张,那么小猴最大可以拼到 \(10\),因为拼 \(11\) 时候数字 \(1\) 卡片只有 \(1\) 张了,不够拼出 \(11\)。
【输入】
一行一个整数 \(n\)。
【输出】
一行一个整数,表示小猴最大可以拼到的整数。
【输入样例】
1
【输出样例】
9
【核心思想】
-
问题分析:给定 \(0\) 到 \(9\) 的数字卡片各 \(n\) 张,从 \(1\) 开始连续拼接正整数,求最大能拼到多少。这是一个贪心模拟 + 逐位检查问题,关键在于从 \(1\) 开始逐个尝试,每次消耗对应数字的卡片,直到某个数字无法拼出。
-
算法选择:
- 贪心递增:从 \(1\) 开始逐个尝试,能拼出则继续,不能则停止
- 逐位消耗:将每个数字的各位分解,检查并消耗对应卡片
-
关键步骤:
- 初始化:
- 读取 \(n\)
num[i] = n(\(i\) 从 \(0\) 到 \(9\)):每种数字卡片初始 \(n\) 张
- 逐个尝试:
ans = 1- 当
check(ans)为真时循环:ans++
- 检查函数
check(x):- 当
x > 0时循环:y = x % 10:取出最低位数字num[y]--:消耗该数字卡片- 若
num[y] < 0:返回false(卡片不足) x /= 10:去掉最低位
- 返回
true
- 当
- 输出
ans - 1(最后一个能拼出的数字)
- 初始化:
-
时间/空间复杂度:
- 时间复杂度:\(O(ans \times \log ans)\),\(ans\) 为答案,每个数字最多 \(\log ans\) 位
- 空间复杂度:\(O(1)\),仅需 \(10\) 个计数变量
-
贪心模拟的核心思想:
- 连续性约束:必须从 \(1\) 开始连续拼,不能跳过,因此贪心逐个尝试是最优策略
- 卡片消耗不可逆:
check函数中直接修改num数组,模拟真实消耗过程,一旦失败无法回退 - 逐位分解:通过
%10和/10逐位提取数字,独立检查每种卡片的剩余量 - 终止条件:当某个数字的卡片耗尽且该数字 needed 时,
check返回false,循环终止 - 适用于"资源有限 + 连续构造"类问题,贪心模拟直观且能保证最优性(因为必须连续)
【算法标签】
模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, num[10]; // 数字数量限制n,数字0-9的剩余数量数组
bool check(int x) // 检查能否用剩余数字组成数字x
{
while (x>0) // 逐位检查
{
int y = x % 10; // 取出最低位
num[y]--; // 该数字使用次数减1
if (num[y]<0) return false; // 如果数字用完,返回false
x /= 10; // 去掉最低位
}
return true; // 可以组成数字x
}
signed main() // 主函数
{
cin >> n; // 输入每个数字最多可用次数
for (int i=0; i<=9; i++) num[i] = n; // 初始化所有数字的剩余数量
int ans = 1; // 从数字1开始尝试
while (check(ans)==true) ans++; // 不断尝试更大的数字
cout << ans - 1 << endl; // 输出能组成的最大数字
return 0; // 程序正常结束
}
【运行结果】
1
9
浙公网安备 33010602011771号