题解:学而思编程 素数加法算式
【题目来源】
学而思编程:素数加法算式
【题目描述】
有一个只含数字 \(1\sim 9\) 的字符串 \(s\),现在要求在字符中插入若干加号,使得字符串成为一个加法算式。(也可以一个都不加)
得到的加法算式的计算结果是素数的算式有多少种?
【输入】
\(1\) 行,\(1\) 个字符串 \(s\)
【输出】
输出结果是素数的算式个数
【输入样例】
124
【输出样例】
1
【核心思想】
-
问题分析:给定只含数字 \(1 \sim 9\) 的字符串 \(s\),需要在字符之间插入若干加号(也可不插),使其成为一个加法算式,统计计算结果为素数的算式个数。例如
124可分割为1+2+4=7、12+4=16、1+24=25、124=124,其中只有7是素数,故答案为 \(1\)。关键观察是:\(n\) 个字符之间有 \(n-1\) 个可分割位置,每个位置有"分割"或"不分割"两种选择,共 \(2^{n-1}\) 种方案,适合用 DFS 枚举。 -
算法选择:
- 深度优先搜索(DFS):枚举每个可分割位置的两种状态(分割/不分割),生成所有可能的加法算式
- 试除法判定素数:对每个算式的结果,用 \(O(\sqrt{x})\) 的试除法判断是否为素数
-
关键步骤:
- 初始化:读入字符串 \(s\),长度 \(n = |s|\),设置 \(c[n] = 1\)(最后一个位置强制分割,确保最后一段数字被计入总和)
- DFS 枚举(
dfs(p),\(p\) 为当前处理的分割位置):- 若 \(p > n - 1\):所有位置已处理完毕,计算当前方案的总和:
- 遍历字符串,根据 \(c[i]\) 的值决定分割或拼接数字
- 若
isp(sum)为真,cnt++ - 返回
- \(c[p] = 0\),递归
dfs(p + 1)(不分割) - \(c[p] = 1\),递归
dfs(p + 1)(分割)
- 若 \(p > n - 1\):所有位置已处理完毕,计算当前方案的总和:
- 素数判定
isp(x):- 若 \(x < 2\),返回
false - 遍历 \(i\) 从 \(2\) 到 \(\lfloor \sqrt{x} \rfloor\):若 \(x \bmod i = 0\),返回
false - 返回
true
- 若 \(x < 2\),返回
- 输出答案:\(cnt\)
-
时间/空间复杂度:
- 时间复杂度:\(O(2^{n-1} \cdot n \cdot \sqrt{S})\),其中 \(S\) 为算式结果的最大值。\(2^{n-1}\) 种方案,每种方案计算总和 \(O(n)\),素数判定 \(O(\sqrt{S})\)
- 空间复杂度:\(O(n)\),递归栈深度和分割状态数组
-
DFS 枚举与剪枝的核心思想:
- 二进制状态枚举:\(n-1\) 个分割位置对应 \(n-1\) 个二进制位,DFS 本质是枚举所有 \(2^{n-1}\) 种二进制状态,每种状态对应一种唯一的分割方案
- 强制边界分割:设置 \(c[n] = 1\) 确保字符串末尾必然形成一个完整的加数,避免最后一段数字被遗漏,简化了总和计算的逻辑
- 延迟计算策略:不在 DFS 过程中实时维护当前总和,而是在叶子节点(所有位置确定后)统一计算,降低了状态维护的复杂度
- 试除法的适用性:由于字符串只含 \(1 \sim 9\) 且长度通常较小(\(n \leq 10\) 左右),算式结果不会太大,试除法足够高效
- 适用于组合枚举、字符串分割、表达式生成等场景,是 DFS 在组合计数问题中的典型应用
【解题思路】

【算法标签】
DFS-一维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int MR = 1e6 + 10;
typedef long long LL;
string s;
int n;
bool isp(long long x)
{
if (x < 2) return false; // 小于2的不是素数
for (int i = 2; i * i <= x; i++) { // 试除法判断素数
if (x % i == 0) return false;
}
return true;
}
int c[11], cnt; // c数组记录是否分割,cnt记录方案数
void dfs(int p) // 递归枚举所有分割方案
{
if (p > n - 1) { // 已经处理完所有分割位置
long long sum = 0, t = (s[0] - '0'); // sum为总和,t为当前数字
for (int i = 1; i <= n; i++) {
if (c[i] == 0) { // 不分割,继续组成数字
t = t * 10 + (s[i] - '0');
} else { // 分割,将当前数字加入总和
sum += t;
t = (s[i] - '0'); // 开始新的数字
}
}
if (isp(sum)) cnt++; // 判断总和是否为素数
return;
}
c[p] = 0; // 在第p个位置不分割
dfs(p + 1);
c[p] = 1; // 在第p个位置分割
dfs(p + 1);
}
int main()
{
cin >> s; // 输入数字字符串
n = s.size(); // 获取长度
c[n] = 1; // 最后一个位置强制分割,确保最后一段数字被加入总和
dfs(1); // 从第一个分割位置开始枚举
cout << cnt << endl;
return 0;
}
【运行结果】
124
1
浙公网安备 33010602011771号