题解:学而思编程 特殊数字2
【题目来源】
学而思编程:特殊数字2
【题目描述】
如果一个十进制正整数能够被它的每一个非零数码整除,则称它为特殊数字,比如 \(408\) 是一个特殊数字,因为 \(408\) 能被 \(4\) 与 \(8\) 整除,而 \(1023\) 不是,因为它不能被 \(2\) 整除。给定一个正整数 \(n\),请判定它是否为特殊数字。
【输入】
第一行包含整数 \(T\),表示共有 \(T\) 组测试数据。
每组数据占一行,包含一个整数 \(n\)。
【输出】
每组数据输出一行结果,如果 \(n\) 是一个特殊数字,输出 Yes;否则,输出 No。
【输入样例】
3
13
1
1024
【输出样例】
No
Yes
Yes
【核心思想】
-
问题分析:给定正整数 \(n\),判断其是否为"特殊数字"——即 \(n\) 能被其每一个非零数码整除。例如 \(408\) 是特殊数字(\(408 \div 4 = 102\),\(408 \div 8 = 51\)),\(1023\) 不是(\(1023 \div 2 = 511.5\))。这是一个大数取模 + 逐位验证问题,关键在于处理 \(n\) 可能非常大的情况,以及高效判断整除性。
-
算法选择:
- 字符串存储:将 \(n\) 作为字符串读入,避免整数溢出
- 大数取模:逐位模拟大数对单个数码取模,\(O(|n|)\) 完成
- 出现标记:用布尔数组
vis[10]标记哪些非零数码在 \(n\) 中出现,避免重复检查
-
关键步骤:
-
初始化:读取 \(T\)(测试组数)
-
处理每组数据:
- 读取数字字符串 \(s\),\(n = s.size()\)
memset(vis, false, sizeof(vis))- 标记出现数码:遍历 \(i\) 从 \(0\) 到 \(n-1\):
vis[s[i] - '0'] = true - 验证整除性:
flag = true- 遍历 \(i\) 从 \(1\) 到 \(9\):
- 若
vis[i] == true且chk(i) == false:flag = false,break
- 若
- 若
flag == true:输出Yes,否则输出No
-
大数取模函数
chk(x):num = 0- 遍历 \(i\) 从 \(0\) 到 \(n-1\):
num = num * 10 + (s[i] - '0')num %= x:每一步取模防止溢出
- 若
num == 0:返回true(可整除),否则返回false
-
-
时间/空间复杂度:
- 时间复杂度:\(O(T \times |n| \times 9)\),每组数据最多检查 \(9\) 个数码,每次取模 \(O(|n|)\)
- 空间复杂度:\(O(|n|)\),存储字符串和标记数组
-
大数逐位取模的核心思想:
- 模运算性质:\((a \times 10 + b) \bmod x = ((a \bmod x) \times 10 + b) \bmod x\),允许逐位计算大数对 \(x\) 的模,无需存储完整数值
- 非零数码筛选:\(0\) 不能作为除数,且 \(0\) 对整除性无约束(任何数都能被 \(0\) 整除无意义),因此只检查 \(1\) 到 \(9\)
- 出现标记去重:同一数码多次出现只需验证一次,
vis数组避免重复计算 - 提前终止:一旦发现某个出现过的数码不能整除 \(n\),立即判定为
No,无需继续检查 - 适用于"大数整除性判定 + 数码约束"类问题,逐位取模将大数运算转化为线性扫描
【算法标签】
字符串入门
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, T;
string s;
bool vis[10]; // 记录数字0-9是否在字符串中出现
// 检查字符串表示的数字是否能被x整除
bool chk(int x)
{
int num = 0;
for (int i = 0; i <= n - 1; i++) // 遍历字符串的每个字符
{
num = num * 10 + (s[i] - '0'); // 模拟大数计算
num %= x; // 取模,防止溢出
}
if (num == 0) // 如果余数为0,说明能被整除
{
return true;
}
return false;
}
int main()
{
cin >> T; // 读取测试用例数量
while (T--) // 处理每个测试用例
{
cin >> s; // 读取数字字符串
n = s.size(); // 获取字符串长度
memset(vis, false, sizeof(vis)); // 重置vis数组
// 记录哪些数字在字符串中出现了
for (int i = 0; i <= n - 1; i++)
{
vis[s[i] - '0'] = true; // 标记数字出现
}
bool flag = true; // 标志是否所有出现的数字都能整除这个数
// 检查1-9中每个在字符串中出现的数字
for (int i = 1; i <= 9; i++)
{
if (vis[i] == true && chk(i) == false) // 如果数字i出现且不能整除
{
flag = false; // 标记为不满足条件
break;
}
}
if (flag == true)
{
cout << "Yes" << endl;
}
else
{
cout << "No" << endl;
}
}
return 0;
}
【运行结果】
3
13
No
1
Yes
1024
Yes
浙公网安备 33010602011771号