1 条题解
-
0
「Genotype」题解
问题分析
这是一个文法推导问题:给定一组产生式规则 ,其中 都是大写字母(基因),需要判断给定的字符串能否由这些规则从起始符号 推导出来,并求最少需要多少个 。
关键点:
- 每个产生式规则将一个基因分裂成两个基因
- 起始符号是 (特种基因)
- 目标字符串由大写字母组成,长度不超过100
- 需要求最少使用多少个 才能产生目标字符串
问题转化
这实际上是一个上下文无关文法(CFG)的最优解析问题。我们可以将其转化为一个区间DP问题。
设目标字符串为 ,长度为 。
状态定义
定义 表示:字符串 (子串)能否由单个基因 推导出来。
但我们需要求的是最少 的数量,所以更好的定义是: 定义 表示:生成子串 所需的最少 的数量。如果不能生成,则 。
状态转移
对于子串 ,有两种生成方式:
-
直接生成:如果存在规则 对应的两个字符(注意规则是分裂成两个基因,不是多个),但这里的 可能很长,所以不能直接匹配。我们需要将 分解为两部分。
-
分裂生成:
- 将 在某个位置 切分为两部分: 和
- 如果存在规则 ,且 可由 生成, 可由 生成
- 那么 就可以生成
算法框架
我们实际上需要两个DP表:
- 生成表 :布尔值,表示子串 能否由单个基因 生成。
- 计数表 :生成子串 所需的最少 数量。
步骤1:计算
初始化:
- 对于每个位置 ,(单个字符可以由对应的基因直接生成)
状态转移: 对于长度 到 : 对于起始位置 到 : 设 对于每个分割点 到 : 对于每条规则 : 如果 ,则
时间复杂度:,其中 是规则数,,最坏 ,太大!
优化
我们需要优化状态转移。观察到:
- 规则只有 种可能,但实际上最多只有 条规则
- 对于固定的 ,我们可以先计算哪些基因可以生成 ,哪些可以生成 ,然后查看规则表
更好的方法是:
- 将规则组织成:对于每对 ,记录所有能生成 的基因
- 这样转移时,对于 和 ,我们可以直接得到
步骤2:计算
初始化:
- 如果 可以由 生成(即 ),否则为
状态转移:
- 直接使用一个 生成整个子串:如果 为真,则
- 将子串分割:$cnt[i][j] = \min_{k=i}^{j-1} (cnt[i][k] + cnt[k+1][j])$
最终答案:
算法流程
预处理规则
- 读取所有规则
- 建立规则表 ,存储所有能生成 的基因 的列表
对每个查询字符串 (长度 )
阶段1:计算 表
// 初始化 for i = 1 to m: for each c in ['A'..'Z']: can[i][i][c] = (s[i] == c) // DP for len = 2 to m: for i = 1 to m-len+1: j = i+len-1 for k = i to j-1: // 获取所有能生成 s[i..k] 的基因集合 set1 // 获取所有能生成 s[k+1..j] 的基因集合 set2 for each X in set1: for each Y in set2: for each c in rules[X][Y]: can[i][j][c] = true阶段2:计算 表
// 初始化 for i = 1 to m: if can[i][i]['S']: cnt[i][i] = 1 else: cnt[i][i] = INF // DP for len = 2 to m: for i = 1 to m-len+1: j = i+len-1 // 方法1:直接用一个S生成 if can[i][j]['S']: cnt[i][j] = 1 else: cnt[i][j] = INF // 方法2:分割 for k = i to j-1: cnt[i][j] = min(cnt[i][j], cnt[i][k] + cnt[k+1][j])输出结果
- 如果 ,输出 "NIE"
- 否则输出
复杂度分析
- 对于每个查询字符串(长度 ):
- 阶段1:,但实际中基因集合很小
- 阶段2:
- 总复杂度:,对于 , 可接受
- 查询数 ,但每个字符串独立处理
- 总复杂度:,最坏 ,可能过大!
进一步优化
实际上,,, 时, 确实太大。需要优化:
优化1:预处理规则矩阵
- 建立 的矩阵,每个元素是一个位集(26位),表示能生成对应基因对的基因集合
- 这样可以在 时间内检查规则
优化2:使用位运算优化 表
- 可以是一个26位的位集,表示哪些基因能生成子串
- 转移时:
- 这里 需要支持位集输入输出
优化3:记忆化搜索 + 剪枝
- 使用记忆化搜索避免重复计算
- 当 已经为1时(直接由S生成),不需要进一步分割
优化4:限制查询字符串长度
- 题目说最多100个字母,但实际可能更短
- 可以统计实际的最大长度
最终算法
使用区间DP + 位运算优化:
- 预处理规则为位集形式
- 对每个查询:
- 计算 (位集)
- 计算
- 输出结果
特殊情况处理
- 空字符串:题目没说,但长度为0时应该输出0(不过题目说最少1个字母)
- 起始符号S:注意规则中可能有其他基因也能生成子串,但我们关心的是最少S的数量
- 无法生成:如果 ,输出 "NIE"
总结
本题是一个经典的文法解析问题,通过区间DP求解。关键点:
- 将问题转化为区间DP
- 使用两个DP表:一个判断能否生成,一个计算最少S的数量
- 使用位运算优化规则匹配
- 注意时间复杂度优化,因为查询数可能很多
- 1
信息
- ID
- 5864
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者