通过率 0% · 提交 0 · 通过 0
标注平台把一条样本的标签序列压缩成了一个数字串:每个标签的类别编号在 1 到 26 之间,直接按顺序拼接,不加分隔符。现在给出压缩后的数字串,请统计它能还原成多少种不同的标签序列。由于答案可能很大,输出对 1000000007 取模后的结果。无法还原时输出 0。
这类题属于算法机考高频题型中「华为 AI 岗 / 序列 DP」方向的高频题型,通常考察对「华为 AI 岗 / 序列 DP」的建模能力与边界条件处理。掌握本题的解题思路后,可举一反三应对同类真题方向,稳步提升机考通过率。
输入一行数字串 s。
输出一行一个整数,表示方案数对 1000000007 取模的结果。
示例 1
输入示例
12
输出示例
2
两种还原方式
示例 2
输入示例
226
输出示例
3
三种还原方式
时间限制 2000 ms · 内存限制 256 MB
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。
这些是真正决定能不能 AC、但通用题解里常被略过的点。
序列生成型 DP 的经典骨架:逐位扫描,每一位问「我能接在谁后面」。转移长得和爬楼梯一模一样(dp[i] = dp[i-1] + dp[i-2]),难点全在合法性条件——0 和 27~30 这些非法编号把两条转移各挂了一道闸。
dp[i] = 前 i 个字符能还原的方案数。第 i 个字符有两种来路:
两条闸都关上时 dp[i] = 0——比如 "30",3 后面跟 0,0 既不能单独成编号,30 又超出 26,整串无解。初始值 dp[0] = 1(空串一种方案),首字符为 '0' 直接输出 0。
|s| 可达 10 万,方案数按斐波那契速度增长,必须对 1e9+7 取模。一个隐蔽的坑:别用「中途 dp 值为 0 就提前退出」当优化——取模后的 0 不代表真实方案数为 0(理论上可能撞上模数的倍数),正确的无解判断只能来自转移条件本身。参考解从头到尾老实转移,不做这种「聪明」优化。
转移只看前两格,两个变量滚动即可,空间 O(1):
prev2, prev1 = 1, (首字符合法 ? 1 : 0)
每一位:cur = (单走贡献 + 两位贡献) % MODO(n) 一遍扫,10 万长度毫无压力。这道题没有部分分空间——要么转移条件写对全过,要么在 0 的三种位置(开头/中间可救/中间无解)上批量挂,建议把 "10"、"100"、"1002" 手算一遍再提交(1、0、2 分别怎么接)。
参考实现两个滚动变量 prev2、prev1,每一位算 cur:s[i] 在 '1'-'9' 时加 prev1,s[i-1:i+1] 在 "10"-"26" 时加 prev2,取模后滚动。两位数判断用整数比较 10 <= int(s[i-1:i+1]) <= 26,比字符逐位比对不容易漏 27~30。
1. "10":1 可单走,10 可两位;但 0 不能单走,所以只有「10」一种,答案 1。 2. "100":第二个 0 前面是 0,既不能单走也组不成 10-26(00 非法),答案 0。 3. "226":2-2-6、22-6、2-26 共 3 种,对齐样例。 4. "1111111111"(十个 1):答案是斐波那契第 11 项 89,验证转移骨架和爬楼梯确实同源。
O(n) 扫 10 万字符,瓶颈不在算法。C++/Java 记得每步取模,乘法不出现所以不会溢出 long,但加法不取模累积几万步也会超 int;Python 无溢出,照样取模保持输出正确。
# 序列 DP:每位问「单独成编号(1-9)?与前一位组两位(10-26)?」
# 转移同爬楼梯骨架 dp[i]=dp[i-1]+dp[i-2],条件不满足的支路记 0;全程取模 1e9+7
import sys
MOD = 1_000_000_007
def solve() -> None:
s = sys.stdin.readline().strip()
if not s or s[0] == "0":
print(0)
return
prev2, prev1 = 1, 1
for i in range(1, len(s)):
cur = 0
if s[i] != "0":
cur = prev1
two = int(s[i - 1:i + 1])
if 10 <= two <= 26:
cur = (cur + prev2) % MOD
prev2, prev1 = prev1, cur
print(prev1 % MOD)
if __name__ == "__main__":
solve()
登录后可查看你在本题的历史提交,以及每次的各用例通过情况。