🔍 2025蓝桥杯备赛Day13——P10984 [蓝桥杯 2023 国 Python A] 残缺的数字
🚀 题目速览
题目难度:⭐⭐⭐(需掌握位运算与组合数学)
考察重点:二进制状态处理、位运算、乘法原理、枚举
P10984 [蓝桥杯 2023 国 Python A] 残缺的数字
题目描述
七段码显示器是一种常见的显示数字的电子元件,它有七个发光管组成:
上图依次展示了数字 0 ∼ 9 0\sim 9 0∼9 用七段码来显示的状态,其中灯管为黄色表示点亮,灰色表示熄灭。根据灯管的亮暗状态,我们可以用一个状态码(状态码是一个 7 7 7 位的二进制数字)来表示一个七段码,令灯管点亮时状态为 1 1 1,灯管熄灭时状态为 0 0 0,按照灯管 A B C D E F G \rm ABCDEFG ABCDEFG 的顺序标识一个七段码,则数字 0 ∼ 9 0 \sim 9 0∼9 的状态码为:
数字 | 状态码 | 数字 | 状态码 |
---|---|---|---|
0 0 0 | 1111110 1111110 1111110 | 5 5 5 | 1011011 1011011 1011011 |
1 1 1 | 0110000 0110000 0110000 | 6 6 6 | 1011111 1011111 1011111 |
2 2 2 | 1101101 1101101 1101101 | 7 7 7 | 1110000 1110000 1110000 |
3 3 3 | 1111001 1111001 1111001 | 8 8 8 | 1111111 1111111 1111111 |
4 4 4 | 0110011 0110011 0110011 | 9 9 9 | 1111011 1111011 1111011 |
小蓝有一个喜爱的数字,长度为
18
18
18 位,每一位用一个七段码显示器来展示
(每位只能是
0
∼
9
0 \sim 9
0∼9,可以包含前导零),由于灯管故障,一些本该点亮的灯管
处于了熄灭状态。例如,对于一个长度为
2
2
2 的数字来说,当两个七段码对应的
状态码分别为:
1011111
1011111
1011111(高位)、
1110011
1110011
1110011(低位)时,原本的数字可能会是:
68
68
68、
69
69
69、
88
88
88、
89
89
89,有 4 种可能的值。
18 18 18 个七段码显示器对应的状态码分别为:
0000011
0000011
0000011,
1001011
1001011
1001011,
0000001
0000001
0000001,
0100001
0100001
0100001,
0101011
0101011
0101011,
0110110
0110110
0110110,
1111111
1111111
1111111,
0010110
0010110
0010110,
0101001
0101001
0101001,
0010110
0010110
0010110,
1011100
1011100
1011100,
0100110
0100110
0100110,
1010000
1010000
1010000,
0010011
0010011
0010011,
0001111
0001111
0001111,
0101101
0101101
0101101,
0110101
0110101
0110101,
1101010
1101010
1101010。
其中每个表示一个七段码对应的的状态码(按照数字的高位到低位给出)。请你
判断下小蓝喜爱的数字有多少种可能的值。
输入格式
无
输出格式
一行一个整数表示答案。
(题目意思就是说18个七段码有多少种有效组合,
有效的例子:
- 二进制解析:
- 对应七段码的灯管状态为:
GFEDCBA = 0000011
- 即只有 G段 和 F段 亮起 !
- 对应七段码的灯管状态为:
- 寻找有效数字:
- 检查数字0-9的原始亮灯状态是否包含G和F段亮起
- 数字1的原始状态码:0110000(GFEDCBA)
- G=0,F=0 → 不满足
- 数字7的原始状态码:1110000
- G=1,F=1 → 满足
- 结论:该状态码对应有效数字可能为7
然后把这些可能在这18位数中进行组合)
🔥 核心解法:位运算 + 组合乘法
🛠️ 实现思路
- 二进制状态编码
- 将每个七段码状态转换为整数(二进制处理)
- 预计算数字0-9的标准七段码二进制值
- 状态匹配检测
- 对每个输入状态码,检查其是否为某数字标准码的子集
- 统计每个位置的有效数字数量
- 组合乘法
- 所有位置的有效数字数量相乘得到最终结果
🛠️ C++代码实现
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 将7位二进制字符串转换为整数
int str_to_bits(const string& s) {
int res = 0;
for (char c : s) { // 遍历每个字符
res = (res << 1) | // 左移腾出新位
(c - '0'); // 转换字符为0/1
}
return res;
}
int main() {
// 数字0-9的标准七段码(字符串形式)
const vector<string> digit_codes = {
"1111110", "0110000", "1101101", "1111001",
"0110011", "1011011", "1011111", "1110000",
"1111111", "1111011"
};
// 预计算数字对应的二进制值
int digit_values[10];
for (int i = 0; i < 10; ++i) {
digit_values[i] = str_to_bits(digit_codes[i]);
}
// 题目给定的18个状态码
const vector<string> input_codes = {
"0000011", "1001011", "0000001", "0100001",
"0101011", "0110110", "1111111", "0010110",
"0101001", "0010110", "1011100", "0100110",
"1010000", "0010011", "0001111", "0101101",
"0110101", "1101010"
};
// 转换输入状态码为整型
vector<int> states;
for (const auto& code : input_codes) {
states.push_back(str_to_bits(code));
}
// 计算总可能性
long long total = 1;
for (int state : states) {
int valid_count = 0;
for (int i = 0; i < 10; ++i) { // 遍历所有数字
// 关键判断:输入状态是数字状态的子集
if ((digit_values[i] & state) == state) {
++valid_count;
}
}
total *= valid_count;
}
cout << total << endl; // 输出最终结果
return 0;
}
📚 关键知识点解析
一、二进制状态处理
操作 | 代码实现 | 作用 |
---|---|---|
字符串转二进制 | `(res << 1) | (c - ‘0’)` |
状态匹配检测 | (digit & input) == input | 验证输入状态是数字状态的子集 |
二、按位或运算符 |
作用:将两个数的二进制对应位进行逻辑或运算(任意一位为1则结果为1)
示例:
Cppint a = 5; // 00000101
int b = 3; // 00000011
int c = a | b; // 00000111(十进制7)
代码中的作用:
res = ... | (c - '0')
将新位(0或1)拼接到结果末尾- 相当于二进制位的动态拼接
三、字符转换 c - '0'
作用:将字符 '0'
或 '1'
转换为整数 0 或 1
原理:
- 字符
'0'
的ASCII码是48,'1'
是49 '0' - '0' = 0
,'1' - '0' = 1
🚨 易错点警示
错误1:位运算优先级错误
// 错误写法:缺少括号导致逻辑错误
if (digit & state == state)
// 正确写法
if ((digit & state) == state)
错误2:二进制转换错误
// 错误:逆序处理导致位顺序错误
for (int i = s.size()-1; i >=0; --i) // 错误处理顺序
// 正确:按字符串顺序处理
for (char c : s) // 从左到右处理
⚡ 性能分析
操作 | 时间复杂度 | 空间复杂度 | 说明 |
---|---|---|---|
预处理数字状态 | O(10) | O(1) | 固定10个数字 |
处理输入状态 | O(18) | O(18) | 固定18个状态码 |
计算有效数 | O(18×10) | O(1) | 常数级运算 |
总复杂度 | O(1) | O(1) | 所有操作均为常数时间 |
🌟 举一反三
变种题1:动态七段码显示
若七段码显示模式可变(如部分段损坏不可用),需修改状态检测逻辑:
// 添加损坏段掩码
int broken_mask = 0b0010000; // 假设G段损坏
if ((digit & (state | broken_mask)) == state) {
// 有效条件需排除损坏段
}
变种题2:多状态可能性查询
若需多次查询不同状态组合,可预先建立数字状态的特征矩阵:
vector<bitset<128>> feature(10); // 每个数字的状态特征
// 预处理所有可能状态
for (int i=0; i<10; ++i) {
for (int s=0; s<128; ++s) {
feature[i][s] = ((digit_values[i] & s) == s);
}
}
答案验证:运行程序输出 254016000,与Python实现结果一致,验证算法正确性。本解法通过位运算优化,在保证可读性的同时达到最优性能,适合蓝桥杯竞赛场景。