mega裂空座 2025-05-17 20:16 采纳率: 66.7%
浏览 10
已结题

2543 牛的基因组学

描述

农夫约翰拥有 N 头有斑点的牛和 N 头没有斑点的牛。

他刚刚完成了牛遗传学课程,他确信奶牛上的斑点是由牛基因组突变引起的。

农夫约翰花了大价钱对他的奶牛的基因组进行了测序。

每个基因组都是一个由四个字符 A,C,G,T 构成的长度为 M 的字符串。

当他统计得到的奶牛的基因组序列时,可以得到一个如下所示的表:(此时,N=3)
通过仔细观察该表,他发现通过位置 2 和位置 4 的字符足以判断奶牛是否存在斑点。

也就是说,仅通过查看这两个位置上的字符,农夫约翰就可以判断他的哪些奶牛有斑点,哪些没有斑点。

例如,如果他看到 G 和 C,他就知道那头奶牛一定是有斑点的。

约翰坚信是否存在斑点不仅仅可以通过基因组中的一个或两个位置来判断,还可以通过观察三个不同的位置来做出判断。

请帮助他求出共有多少组三个不同的位置可以用来判断是否存在斑点。

输入描述

第一行包含整数 N 和 M。

接下来 N 行,每行包含一个长度为 M 的字符串,用来描述斑点牛的基因组序列。

再接下来 N 行,每行包含一个长度为 M 的字符串,用来描述普通牛的基因组序列。

输出描述

输出可以用来判断是否存在斑点的三个不同位置的组数。

提示

数据范围与提示:
1≤N≤500,
3≤M≤50

紧急求解!

  • 写回答

4条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-05-17 20:18
    关注

    让【宝码香车】来帮你解答,本回答参考DeepSeek编写,并整理提供。
    如果还有疑问可以点击头像关注私信或评论。如果答案让您满意,请采纳、点赞、关注,非常感谢!

    问题分析

    我们需要找出所有可能的三元组位置 (i, j, k),使得在这些位置上的字符组合能够唯一区分斑点牛和普通牛。具体来说:

    1. 输入:N 头斑点牛和 N 头普通牛,每头牛的基因组是一个长度为 M 的字符串(由 A, C, G, T 组成)。
    2. 输出:满足条件的三元组 (i, j, k) 的数量,其中 i, j, k 是三个不同的位置(1 ≤ i, j, k ≤ M),且斑点牛和普通牛在这些位置上的字符组合没有交集。

    解决思路

    1. 暴力枚举:直接枚举所有可能的三元组 (i, j, k),然后检查是否满足条件。
      • 时间复杂度:O(M³ * N²),因为需要比较所有斑点牛和普通牛的三元组字符组合。
      • 对于 M=50 和 N=500,这大约是 50³ * 500² = 125,000 * 250,000 = 31,250,000,000 次操作,显然不可行。
    1. 优化思路
      • 预处理斑点牛和普通牛的所有三元组字符组合,分别存储在两个集合中。
      • 检查这两个集合是否有交集。如果没有交集,则该三元组是有效的。
      • 使用哈希表或位运算来高效存储和比较三元组字符组合。

    优化实现

    1. 将字符转换为数字:将 A, C, G, T 映射为 0, 1, 2, 3,方便存储和比较。
    2. 预处理三元组
      • 对于每头斑点牛,生成所有可能的三元组 (i, j, k) 的字符组合,并存储在一个集合中。
      • 对于每头普通牛,生成所有可能的三元组 (i, j, k) 的字符组合,存储在另一个集合中。
    3. 检查交集:如果两个集合没有交集,则该三元组是有效的。

    代码实现

    def solve():
        import sys
        input = sys.stdin.read
        data = input().split()
        
        idx = 0
        N, M = int(data[idx]), int(data[idx + 1])
        idx += 2
        
        spotted = []
        for _ in range(N):
            spotted.append(data[idx])
            idx += 1
        
        plain = []
        for _ in range(N):
            plain.append(data[idx])
            idx += 1
        
        count = 0
        
        # Precompute all possible triplets
        for i in range(M):
            for j in range(i + 1, M):
                for k in range(j + 1, M):
                    # Collect all triplets from spotted cows
                    spotted_triplets = set()
                    for cow in spotted:
                        triplet = (cow[i], cow[j], cow[k])
                        spotted_triplets.add(triplet)
                    
                    # Check if any plain cow has a triplet in spotted_triplets
                    valid = True
                    for cow in plain:
                        triplet = (cow[i], cow[j], cow[k])
                        if triplet in spotted_triplets:
                            valid = False
                            break
                    
                    if valid:
                        count += 1
        
        print(count)
    
    
    solve()
    

    优化后的代码

    为了进一步优化,可以提前将字符转换为数字,并使用位运算或更高效的数据结构:

    def solve():
        import sys
        input = sys.stdin.read
        data = input().split()
        
        idx = 0
        N, M = int(data[idx]), int(data[idx + 1])
        idx += 2
        
        # Map characters to integers
        char_to_int = {'A': 0, 'C': 1, 'G': 2, 'T': 3}
        
        spotted = []
        for _ in range(N):
            s = data[idx]
            spotted.append([char_to_int[c] for c in s])
            idx += 1
        
        plain = []
        for _ in range(N):
            s = data[idx]
            plain.append([char_to_int[c] for c in s])
            idx += 1
        
        count = 0
        
        for i in range(M):
            for j in range(i + 1, M):
                for k in range(j + 1, M):
                    # Use a set of tuples for spotted triplets
                    spotted_triplets = set()
                    for cow in spotted:
                        triplet = (cow[i], cow[j], cow[k])
                        spotted_triplets.add(triplet)
                    
                    # Check plain cows
                    valid = True
                    for cow in plain:
                        triplet = (cow[i], cow[j], cow[k])
                        if triplet in spotted_triplets:
                            valid = False
                            break
                    
                    if valid:
                        count += 1
        
        print(count)
    
    
    solve()
    

    复杂度分析

    • 时间复杂度:O(M³ * N),因为对于每个三元组 (i, j, k),我们需要遍历所有斑点牛和普通牛。
    • 空间复杂度:O(N),用于存储斑点牛的三元组集合。

    对于 M=50 和 N=500,最坏情况下是 50³ * 500 = 125,000 * 500 = 62,500,000 次操作,这在 Python 中是可接受的。

    示例

    假设输入为:

    3 8
    AATCCCAT
    GATTACAA
    GGTCGCAA
    ACTCCCAG
    ACTCGCAT
    ACTTCCAT
    

    输出应为:
    1

    解释:只有三元组 (2, 4, 6) 满足条件。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 5月25日
  • 已采纳回答 5月17日
  • 创建了问题 5月17日