#19307. 小麦的株高
小麦的株高
之前我们已经覆盖了分子生物学(DNA/RNA)、细胞生物学(细胞生命历程)、进化论(自然选择)。这一次,我们将目光转向遗传学,特别是 “多基因遗传”(Polygenic Inheritance)这一高中生物必修二中的难点和重点。
这道题目考察的是字符串处理、桶计数(Bucket Count) 以及 前缀和(Prefix Sum) 优化。难度定位 GESP 5级(约等于 CSP-J T2)。
题目:小麦的株高 (Height of Wheat)
【背景知识讲解】
在高中生物必修二《遗传与进化》中,我们学习了孟德尔的豌豆实验,那是典型的单基因遗传(比如高茎D对矮茎d是显性)。 但在自然界中,许多性状(如人的身高、皮肤颜色,小麦的株高、籽粒颜色等)并不是由一对基因决定的,而是由多对基因共同决定的。这被称为**“多基因遗传”**(Polygenic Inheritance)。
多基因遗传有以下特点:
- 累加效应(Additive Effect):显性基因(用大写字母表示,如 A, B, C...)对性状有增强作用。显性基因的数量越多,表现出的性状越强(例如长得越高)。
- 不分主次:各个基因之间地位平等,AABBcc 和 aaBBCC 的表现型是一样的,因为它们都含有 4 个显性基因。
- 环境影响:虽然题目中我们暂时忽略环境因素,只考虑基因型。
假设某种小麦的株高由 对基因控制(例如 Aa, Bb, Cc...)。
- 基础高度为 。
- 每含有一个显性基因(大写字母),株高就增加 。
- 例如:基因型
AaBBcc含有 3 个显性基因(A, B, B),其株高就是 。
【题目描述】
农业研究所种植了 株小麦。为了研究遗传规律,实验员测序得到了每一株小麦的基因型字符串 。 基因型字符串由若干对等位基因组成(如 "AaBbCC"),只包含英文字母,且保证是成对出现的(即长度为偶数)。
为了快速筛选育种,研究员需要频繁地进行 次查询。 每次查询给出一个株高范围 (闭区间),请你计算:在这 株小麦中,有多少株的显性基因数量恰好落在 这个范围内?
注意:
- 我们只关心显性基因的数量(即大写字母的个数)。
- 输入保证字符串长度固定为 (即 对基因)。
【输入格式】
第一行包含三个整数 ,分别表示小麦的株数、查询次数和基因对数。 接下来 行,每行包含一个长度为 的字符串 ,表示第 株小麦的基因型。 接下来 行,每行包含两个整数 ,表示查询的显性基因数量范围()。
【输出格式】
对于每次查询,输出一行一个整数,表示满足条件的小麦数量。
【样例数据】
输入:
5 3 3
AaBbCc
aabbcc
AABBCC
AaBBCc
aaBbcc
1 3
0 2
4 6
输出:
2
2
2
样例解释: 共有 5 株小麦,基因对数 (字符串长度6,最大显性数为6)。
AaBbCc: 大写 A, B, C,共 3 个。aabbcc: 没有大写,共 0 个。AABBCC: 全是大写,共 6 个。AaBBCc: 大写 A, B, B, C,共 4 个。aaBbcc: 大写 B,共 1 个。
统计结果(显性数 频率):
- 0个: 1株 (第2株)
- 1个: 1株 (第5株)
- 3个: 1株 (第1株)
- 4个: 1株 (第4株)
- 6个: 1株 (第3株)
查询处理:
- 查询
[1, 3]: 包含显性数为 1, 2, 3 的。对应第 5 株(1个) 和 第 1 株(3个)。共 2 株。 - 查询
[0, 2]: 包含显性数为 0, 1, 2 的。对应第 2 株(0个) 和 第 5 株(1个)。共 2 株。 - 查询
[4, 6]: 包含显性数为 4, 5, 6 的。对应第 4 株(4个) 和 第 3 株(6个)。共 2 株。
【数据范围】
- 对于 100% 的数据:。
- (即字符串长度不超过 100,显性基因数量最大为 100)。
一、 思路提示
- 直接暴力的局限性:
- 如果我们对每一次查询,都去遍历这 株小麦,检查它们的显性基因数是否在 之间。
- 复杂度会是 。当 都是 时,总运算量达到 ,这在 1 秒内肯定跑不完(通常限制 )。
- 观察数据的特征:
- 和 很大,但是 很小!
- 显性基因的数量最多只有 个。
- 这意味着,虽然有 10万株小麦,但它们的“得分”(显性基因数)只有 0 到 100 这几种可能。
- 桶排序思想 (Bucket/Frequency Array):
- 我们可以先遍历一遍所有小麦,统计出:显性基因为 0 的有多少株?为 1 的有多少株?... 为 100 的有多少株?
- 存入一个数组
cnt[],其中cnt[x]表示显性基因数为x的小麦数量。
- 前缀和优化 (Prefix Sum):
- 现在的查询变成了:求数组
cnt在下标 区间的和。 - 虽然区间长度很小(最多100),直接循环求和 也能过。但更优的做法是使用前缀和。
- 构建数组
sum[i] = cnt[0] + cnt[1] + ... + cnt[i]。 - 那么区间 的和就是
sum[R] - sum[L-1]。 - 这样查询复杂度降为 。
- 现在的查询变成了:求数组
二、 预备知识点总结
- 字符串遍历:判断字符是大写还是小写(
'A' <= c && c <= 'Z')。 - 桶计数(Frequency Array):利用数据范围较小的特性进行统计。
- 前缀和(Prefix Sum):经典的 解决静态区间求和问题的技巧。
三、 启发式教学:草稿纸上的推理过程
教练:“面对 10万次提问,如果你每次都去田里(数组)重新数一遍,天都要黑了。有没有办法先把数据整理好?”
-
整理数据(预处理):
- 假设 ,最大得分是 6。
- 我们画 7 个桶,编号 0 到 6。
- 拿到第一株
AaBbCc,数一下大写字母,3个。在 3号桶 放一颗豆子。 - 拿到第二株
aabbcc,数一下大写字母,0个。在 0号桶 放一颗豆子。 - ... 全部放完。
- 这时候,
cnt数组可能是:[1, 1, 0, 1, 1, 0, 1](对应 0~6 分的株数)。
-
回答问题:
- 问题来了:“请问显性基因数在 1 到 3 之间的有多少?”
- 你只需要看桶:1号桶 + 2号桶 + 3号桶。
1 + 0 + 1 = 2。- 如果问题是 0 到 100?那就要加 100 次,稍微有点慢。
-
进一步优化(前缀和):
- 我们可以做一个“累计表格”
sum。 sum[0]= 0号桶sum[1]= 0号 + 1号sum[2]= 0号 + 1号 + 2号- ...
- 如果问
[L, R],其实就是sum[R](0到R的总数) 减去sum[L-1](0到L-1的总数,也就是要把左边不需要的减掉)。
- 我们可以做一个“累计表格”
-
复杂度验证:
- 数大写字母: 次操作。很快。
- 回答查询: 次操作。飞快。
- 完全满足题目要求。
四、 读题关键词总结
- 很大 暗示不能用双重循环,查询必须极其高效。
- “数量” / “范围” 典型的区间求和问题。
- 很小 (基因对数) “值域”很小,提示使用桶(数组)来统计频率。
- “只关心数量” 字符串的具体内容不重要,重要的是大写字母的个数,这是抽象建模的第一步。