1 条题解
-
0
D. 数学问题 详细题解
题目重述
给定一个长度为 ()的数字字符串 。需要在 个数字之间插入恰好 个运算符(每个运算符可以是加法 或乘法 ),运算符不能放在字符串两端,也不能连续放置,且数字的顺序不能改变。求这样得到的合法算术表达式的最小可能计算结果。算术表达式遵循先乘后加的运算顺序。
例如 时,一种最优表达式为 。
核心观察
-
由于恰好要插入 个运算符,而数字有 个,运算符必须放在每两个相邻数字之间,因此每个间隙必须恰好有一个运算符。换句话说,表达式由 个数字(可能由多位数字组成)和它们之间的 个运算符构成,其中运算符是固定的 或 ,但每个位置必须选一个。然而题目要求插入 个符号,这意味着有 个间隙中的 个被填上符号,剩下一个间隙不填符号,即相邻两个数字被视为一个多位数。因此,最终表达式实际上是:将字符串 分成若干个数字块,每个块是一个连续的数字子串(不含前导零的限制,例如
"09"被视为整数 ),块与块之间用运算符连接,运算符的个数等于块的个数减 ,且必须恰好等于 。而块的个数 = 数字的个数 - 未放运算符的间隙数 = ?更简单:原字符串有 个字符,我们选择恰好 个间隙放入运算符,那么剩下的 个间隙不放入运算符,因此会形成 个数字块(因为 个数, 个间隔,少放一个运算符就会合并两个相邻数字为一个多位数,从而总块数减少 ,即 块)。所以表达式正好由 个数字块组成,这些数字块是原字符串的某种划分,每个块的长度至少为 ,且恰好有 个运算符。 -
换言之,我们只需要决定哪一对相邻数字被合并成一个两位数(也可以合并成更多位吗?因为只有 个运算符,而 个间隙,只能有一个间隙不插运算符,所以只能合并一对相邻数字,即产生一个两位数,其余数字仍然保持个位。例如 , 个间隙,只放 个运算符,有 个间隙不放,所以只有一处合并,其他都是单个数字。注意:如果 ,合并后的两位数字仍可以与相邻数字继续合并吗?不能,因为只少放了一个运算符,只能形成一次“合并”,即只有一个两位数字,其余都是个位。因此最终表达式由 个数字构成,其中 个是个位数字,一个是两位数(可能含有前导零,如
"09"视为 )。所以问题转化为:枚举哪两个相邻位置被合并成两位数,然后在这 个数字之间放置 个运算符(每个间隙必须放,因为 个数字之间正好有 个间隙,每个间隙必须放运算符),从而形成一个由加法和乘法组成的表达式,求其最小值。
动态规划计算最小值
一旦确定了 个数字的序列(记为 ,长度 ),我们需要在它们之间插入运算符(每个间隙放 或 ),使得整个表达式的结果最小。注意运算顺序:先乘法后加法。这是经典的“表达式最小化”问题,可以用区间 DP 或基于加法分割的 DP 解决。
设 表示前 个数字组成的前缀表达式的最小结果。则转移时,考虑最后一段连续相乘的因子,即 $dp[i] = \min_{0 \le j < i} (dp[j] + \text{product}(j+1, i))$,其中 表示从第 个到第 个数字的乘积。因为乘法优先级高,我们可以将表达式视为若干乘积项的和,每个乘积项是一段连续数字(不能包含加号)。而由于我们没有括号,数字顺序固定,所以每个加法分割点对应一个乘积段。因此 DP 是正确的。
由于数字值可能很大(两个数相乘可能超过 ,且 ,但 ,单个数字最大为 (两位数),乘积最大约为 ,远超 位整数范围。因此 DP 中需要处理溢出。观察题目要求输出最小值,而答案不会太大(因为可以全部用加法,最大值不超过 左右?实际两位数最大为 ,且可以用加法避免大数),事实上最小值很可能较小。但 DP 过程中乘积可能溢出,我们可以设置一个阈值(如 ),当乘积超过该阈值时,认为其不可能成为最优(因为加法部分总和至少为 ,而乘积过大,不会优于其他方案),从而忽略。
算法步骤
- 读入 和字符串 。若 ,直接输出整数 (无法插入任何运算符)。
- 初始化答案 。
- 枚举所有可能合并的位置 ( 到 ),即将 和 合并成一个两位数,其余字符保持个位,得到数字列表
nums。- 注意合并后的数字可能是
09,应解析为 。
- 注意合并后的数字可能是
- 对每个
nums调用 DP 求最小值:- 令 。
- 初始化 DP 数组 ,。
- 对于 到 : 遍历 到 : 计算 。 若计算过程中乘积溢出(超过一个很大的上界,如 ),则跳过。 更新 。
- 得到 。
- 取所有 的最小值作为答案输出。
正确性证明
- 合并唯一性:由于必须插入恰好 个运算符,而间隙有 个,所以恰好有一个间隙不放运算符,即恰好有一对相邻数字被合并成一个两位数。枚举所有可能合并位置即可覆盖所有情况。
- DP 正确性:对于固定数字序列,表达式可以看作若干个“乘段”的和,每个乘段是一段连续数字的乘积。因为乘法优先,表达式等价于将这些乘段相加。DP 状态 表示前 个数字所能得到的最小和。转移时枚举最后一个乘段的起始位置 ,则前 个数字的最小和为 ,再加上最后一个乘段的乘积,取最小值即可。这覆盖了所有可能的加法分割。
- 溢出处理:由于所有数字 ,且乘段长度不超过 ,乘积可能极大。但最优解中倾向于使用加法来避免大数,因此当乘积超过一个合理阈值(比如 )时,它一定不会优于将所有乘段都用加法得到的结果(因为加法总和至少为 ,而乘积过大,不可能成为最小)。实际实现中可以直接跳过,或者使用大整数,但无需。
复杂度
- 枚举合并位置:。
- 每个合并位置进行一次 DP: 最坏(计算乘积时内层循环),,乘积计算也是 ,因此总 ,对于 但 的和未限制(实际 ),仍然非常快。
边界情况
- 字符串包含
0:乘积可能为 ,这会使表达式结果变成 ,通常是最优值。DP 中应正确处理。 - 前导零:合并后的两位数如
01应解析为 ,代码中直接使用(s[j]-'0')*10 + (s[j+1]-'0')即可得到整数 。 - :无法插入任何运算符,直接输出原数。
示例验证
- ,。合并位置 :,只能放一个运算符,可得到 或 ,最小值 。合并 :,得到 ,,最小值 。全局最小值 ,与样例输出一致。
- ,。枚举合并得 长度 ,通过 DP 可得到 (例如 ),正确。
总结
本题的关键在于理解运算符数量限制导致只有一对相邻数字可以被合并成两位数,从而将原问题简化为:枚举合并位置,然后对得到的 个数字序列进行 DP 求最小表达式值。DP 采用加法分割的思路,利用乘法优先级特性,以 时间求解。由于 很小,暴力枚举即可。注意处理数字
0和溢出。 -
- 1
信息
- ID
- 6988
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者