#19306. 破译遗传密码

破译遗传密码

这一次,我们将目光投向高中生物必修二《遗传与进化》中关于 基因表达(Translation) 的核心机制——遗传密码子的破译

这道题目考察的是字符串处理模运算(Modulo Arithmetic)以及多路状态扫描的思想。难度定位在 GESP 5级(约等于 CSP-J T2/T3)。


题目:破译遗传密码 (Deciphering the Genetic Code)

【背景知识讲解】

在生物体内,mRNA(信使RNA)携带遗传信息指导蛋白质的合成,这个过程叫做翻译。 mRNA上每 3 个相邻的碱基决定一个氨基酸,这 3 个碱基称为一个密码子(Codon)

翻译过程有严格的规则:

  1. 起始密码子:翻译通常从 AUG 开始(该密码子编码甲硫氨酸)。
  2. 终止密码子:翻译在遇到 UAAUGAUAG 时停止(这三个密码子不编码氨基酸,只代表结束)。
  3. 读码框(Reading Frame):核糖体在读取序列时,是连续地、不重叠地每 3 个碱基读一次。

例如序列 ...C AUG GCU UCA UAA G...

  • 只要识别到 AUG,核糖体就开始工作,翻译出第一个氨基酸。
  • 接着读 GCU(第2个)、UCA(第3个)。
  • 遇到 UAA,翻译结束。
  • 这条多肽链的长度就是 3 个氨基酸。

但是,mRNA序列是连续的字符,我们不知道核糖体是从第0个字符、第1个字符还是第2个字符开始读的(这被称为3种阅读框)。你的任务是找出其中能翻译出的最长的那条肽链。

【题目描述】

给定一个长度为 NN 的 mRNA 序列 SS(只包含 'A', 'U', 'C', 'G')。 请你寻找满足以下条件的最长子串:

  1. 该子串以 AUG 开头。
  2. 该子串以 UAAUGAUAG 结尾。
  3. 起始子串和终止子串之间(包括起始,不包括终止)的碱基数量必须是 3 的倍数。
  4. 在起始和终止之间,不能包含其他的终止密码子(即一旦遇到终止就立刻结束)。

请输出该最长子串所能翻译成的氨基酸数量。 (注:起始的 AUG 算 1 个氨基酸,结尾的终止密码子不算氨基酸)。 如果序列中找不到任何符合要求的片段,输出 0。

【输入格式】

第一行包含一个整数 NN,表示 mRNA 序列的长度。 第二行包含一个长度为 NN 的字符串 SS

【输出格式】

输出一个整数,表示最长多肽链包含的氨基酸数量。

【样例数据】

输入:

13
CAUGUUUUUUUAG

输出:

3

【样例解释】

我们需要对 mRNA 序列进行三种不同“读码框(Frame)”的扫描,以寻找符合条件的最长多肽链:

1. 尝试读码框 1(从下标 0 开始,每次跳 3 个):

  • 下标 0: CAU (不是起始)
  • 下标 3: GUU
  • 下标 6: UUU
  • 下标 9: UUA
  • ...
  • 结果:未发现起始密码子 AUG,该读码框无解。

2. 尝试读码框 2(从下标 1 开始,每次跳 3 个):

  • 下标 1: AUG \rightarrow 发现起始密码子!(开始翻译,当前氨基酸数:1)
  • 下标 4: UUU \rightarrow 普通密码子(当前氨基酸数:2)
  • 下标 7: UUU \rightarrow 普通密码子(当前氨基酸数:3)
  • 下标 10: UAG \rightarrow 发现终止密码子!
  • 结果:翻译结束。该片段为 AUG - UUU - UUU
  • 长度计算:虽然跨度包含终止子,但题目要求输出氨基酸数量(含起始,不含终止)。
    • 计算公式:(101)/3=3(10 - 1) / 3 = 3
    • 该链长度为 3

3. 尝试读码框 3(从下标 2 开始,每次跳 3 个):

  • 下标 2: UGU (不是起始)
  • 下标 5: UUU
  • 下标 8: UUA
  • ...
  • 结果:未发现起始密码子 AUG,该读码框无解。

综合结论: 所有可能的翻译结果中,最长的长度为 3。


【补充测试点建议】

为了保证测试数据的完备性,建议在后台数据中包含以下情况(数据生成器代码已覆盖):

  1. 多条链竞争:序列中有两条合法的链,一条长度2,一条长度5,程序需输出5。
  2. 嵌套干扰:例如 AUG...AUG...UAA。根据生物学规则(也是最长匹配贪心逻辑),通常一旦遇到起始就开始翻译,直到终止。如果中间遇到AUG,视为普通甲硫氨酸。如果这题逻辑是“寻找最长”,那么我们只需记录最外层的即可(代码逻辑已涵盖)。
  3. 无解情况:整个序列没有 AUG,或者有 AUG 但后面直到末尾都没有终止密码子。输出 0。
  4. 跨越边界AUGN3N-3 的位置,后面不够 3 个字符,无法形成密码子。

【数据范围】

  • 对于 100% 的数据:1N1,000,0001 \le N \le 1,000,000
  • 字符串仅包含 'A', 'U', 'C', 'G'。

一、 思路提示

  1. 三种“平行世界”

    • 因为密码子是 3 个一组,所以只有三种读取方式:
      • 从下标 0,3,6,0, 3, 6, \dots 开始读。
      • 从下标 1,4,7,1, 4, 7, \dots 开始读。
      • 从下标 2,5,8,2, 5, 8, \dots 开始读。
    • 这就是所谓的模 3 同余。我们可以写一个外层循环 frame = 0 到 2,分别处理这三种情况。
  2. 状态机的思想

    • 对于每一个阅读框(Frame),我们遍历字符串。
    • 我们需要一个变量 start_index 来记录“当前是否正在翻译中”。
      • 初始状态:start_index = -1(表示还没找到 AUG)。
      • 如果你读到了 AUG 并且 start_index == -1:说明新的肽链开始了,记录 start_index = 当前下标
        • 思考:如果 start_index != -1(已经开始了)又读到了 AUG 怎么办?生物学上这只是一个普通的甲硫氨酸,继续翻译即可,不需要更新 start_index(因为我们要找最长的,显然起点越早越好)。
      • 如果你读到了 UAA/UGA/UAG 并且 start_index != -1:说明肽链结束了
        • 计算长度:(当前下标 - start_index) / 3
        • 更新最大值 max_len
        • 重置状态start_index = -1。准备寻找下一条肽链。
  3. 时间复杂度

    • 每个字符最多被访问常数次(3 个 Frame,每个 Frame 访问一遍)。
    • 总复杂度 O(N)O(N)。符合 10610^6 的要求。

二、 预备知识点总结

  1. 字符串子串提取/比较:能够快速判断 S[i]...S[i+2] 是否等于 "AUG"。
  2. 模运算与步长循环:理解 for(int i = frame; i < N; i += 3) 的含义。
  3. 贪心/状态维护:在一次扫描中,通过维护“最早的起点”来获得“最长的长度”。

三、 启发式教学:草稿纸上的推理过程

教练:“我们拿这个序列来做实验:A A U G C C C A U G U U U U A A。” 下标:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

步骤 1:Frame 0 (从下标0开始,看 0, 3, 6...)

  • i=0: AAU -> 不是。
  • i=3: GCC -> 不是。
  • ... 这一轮好像没发现 AUG。pass。

步骤 2:Frame 1 (从下标1开始,看 1, 4, 7...)

  • i=1: AUG -> 发现起始! 标记 start = 1
  • i=4: CCC -> 继续。
  • i=7: AUG -> 这是中间的氨基酸,不管它,继续(我们要最长的,起点不变)。
  • i=10: UUU -> 继续。
  • i=13: UAA -> 发现终止!
    • 结算:当前位置 13。起点 1.
    • 长度 = (13 - 1) / 3 = 12 / 3 = 4。
    • 这段是:AUG, CCC, AUG, UUU。长度为 4。
    • 重置 start = -1

步骤 3:Frame 2 (从下标2开始,看 2, 5, 8...)

  • i=2: UGC -> 不是。
  • ...

教练:“看,通过分三次扫描,我们绝对不会漏掉任何一种可能性。而且逻辑非常清晰,不会乱。”


四、 读题关键词总结

  1. “最长” \rightarrow 需要一个变量 max_ans 维护全局最大值。
  2. “3的倍数” / “密码子” \rightarrow 提示我们使用 step = 3 的循环,并处理 3 种偏移量。
  3. “不包含其他终止” \rightarrow 说明这是一个简单的线性扫描,遇到终止必须结算,不能跳过。

这道题目结合了生物学中“阅读框”的概念,非常适合用来练习字符串处理和逻辑思维。希望你喜欢!