Leetcode 2954. Count the Number of Infection Sequences

  • Leetcode 2954. Count the Number of Infection Sequences
    • 1. 解题思路
    • 2. 代码实现
  • 题目链接:2954. Count the Number of Infection Sequences

1. 解题思路

这道题其实思路上还是挺简单的,就是一个数学问题,还是那种不太难的数学问题。

显然, m m m个生病的人将所有的 n n n个人分成了 n − m + 1 n-m+1 nm+1段,其中头尾两段的传播方向只能是单向的,而剩余的 m − 1 m-1 m1段则每一段都有 2 x i − 1 2^{x_i-1} 2xi1种传播序列( x i > 0 x_i>0 xi>0)。

此时,总的传播序列数目就为:

Π i = 1 m − 1 2 x i − 1 \mathop{\Pi}\limits_{i=1}^{m-1}2^{x_i-1} i=1Πm12xi1

然后,各段序列之间是可以有不同的组合方式的,而这个就是一个排列组合问题,对应的序列可能性就是:

Π i = 0 m C ∑ j ≤ i x i x i \mathop{\Pi}\limits_{i=0}^{m} \mathop{C}_{\sum\limits_{j \leq i} x_i}^{x_i} i=0ΠmCjixixi

将两式相乘即可得到我们总的可能的序列数目。

但是实际在做的时候一直遇到超时问题,因为 C n m = n ! m ! ( n − m ) ! C_n^m = \frac{n!}{m!(n-m)!} Cnm=m!(nm)!n!这个计算是很繁琐的,而且还有同余的问题,就一直处理不好。

最后是看了一下其他大佬的解答才豁然开朗,发现算法还是这么个算法,但是优化点在于说提前先算好 n ! n! n!并记录下来,然后对于 C n m C_n^m Cnm的计算就不用每次都反复求一遍了。

唉,感觉自己还是傻了……

2. 代码实现

给出python代码实现如下:

MOD = 10**9 + 7

@lru_cache(None)
def get_facts():
    facts = [1 for _ in range(10**5+1)]
    for i in range(2, 10**5+1):
        facts[i] = i * facts[i-1] % MOD
    return facts

FACTS = get_facts()
def C(n, m):
    return FACTS[n] * pow(FACTS[m], -1, mod=MOD) * pow(FACTS[n-m], -1, mod=MOD) % MOD

class Solution:
    def numberOfSequence(self, n: int, sick: List[int]) -> int:
        
        if len(sick) == n:
            return 0

        a, b = sick[0]-0, n-1-sick[-1]
        ans = 1 * C(a+b, a)
        s = a + b
        m = len(sick)
        for i in range(m-1):
            k = sick[i+1] - sick[i]-1
            if k > 0:
                s += k
                ans = ans * pow(2, k-1, mod=MOD) * C(s, k) % MOD
        return ans

提交代码评测得到:耗时404ms,占用内存20.6MB。

你可能感兴趣的:(leetcode笔记,leetcode,2954,leetcode,hard,leetcode周赛374,leetcode题解,排列组合)