📜  计算具有相等的LCM和HCF的长度为k的子序列数(1)

📅  最后修改于: 2023-12-03 15:12:01.686000             🧑  作者: Mango

计算具有相等的LCM和HCF的长度为k的子序列数

在本题中,需要计算长度为 k 的子序列中,有多少个子序列的最大公约数和最小公倍数相等。

解题思路

首先,我们需要知道两个数 a 和 b 的最小公倍数 LCM 和最大公约数 HCF 满足以下关系:

LCM * HCF = a * b

因此,如果一个子序列的最大公约数和最小公倍数相等,那么它们一定满足:

LCM = HCF = x

其中 x 是子序列中的某个数。因此,我们可以枚举 x,然后计算包含 x 的子序列中有多少个满足条件的子序列,再将所有的情况累加起来即可。

具体来说,我们可以用一个 map 来记录子序列中 x 的出现次数,然后计算以每个 x 为最大公约数和最小公倍数的子序列数目。这一步可以用数论知识计算,具体来说,对于一个数 x,以它为最大公约数和最小公倍数的子序列个数为:

C(x) = 2^(cnt(x) - 1) - 1

其中 cnt(x) 表示 x 在子序列中出现的次数。这个式子的推导过程比较复杂,这里不再赘述,感兴趣的读者可以自行查阅相关资料。

最后,将所有以 x 为最大公约数和最小公倍数的子序列数目相乘即可得到该子序列中满足条件的子序列数目。

代码实现

下面是用 Python 实现的完整代码:

def count_subsequences(arr, k):
    cnt = {}
    res = 0
    for i in range(len(arr)):
        x = arr[i]
        if x in cnt:
            cnt[x] += 1
        else:
            cnt[x] = 1
        if i >= k - 1:
            lcm = x
            hcf = x
            for j in range(i, i - k, -1):
                lcm = lcm * arr[j] // math.gcd(lcm, arr[j])
                hcf = math.gcd(hcf, arr[j])
            if lcm == hcf:
                prod = 1
                for c in cnt:
                    if c != x:
                        prod *= 2**(cnt[c] - 1)
                res += prod * (2**(cnt[x] - 1) - 1)
            cnt[arr[i - k + 1]] -= 1
            if cnt[arr[i - k + 1]] == 0:
                cnt.pop(arr[i - k + 1])
    return res

在上面的代码中,arr 是输入的序列,k 是子序列的长度。我们首先用一个 map 来统计当前窗口中各个数的出现次数,然后计算以每个数为最大公约数和最小公倍数的子序列数目,最后将所有的数的结果相乘即可得到总的结果。为了方便计算,我们在维护窗口的过程中,将每个超出窗口大小的数的出现次数减一,当它的出现次数减为 0 时,将其从 map 中移除。

总结

本题是一道比较典型的数论问题,需要根据最大公约数和最小公倍数的性质计算子序列的个数。这个问题涉及到一些数论知识,需要一定的数学基础,但是思路比较清晰,代码也比较简单,只要掌握了相关知识点,就可以快速实现。