📌  相关文章
📜  包含不同素数的,长度最大为K的子序列的计数(1)

📅  最后修改于: 2023-12-03 14:50:25.678000             🧑  作者: Mango

包含不同素数的,长度最大为K的子序列的计数

问题描述

给定一个长度为N的正整数序列,求其中包含不同素数的子序列个数,且子序列长度不超过K。

解题思路

这道题需要用到数学中的容斥原理。我们以包含2、3、5三个素数为例:

  • 不考虑长度限制,包含2、3、5三个素数的子序列个数为:$2^x3^y5^z$,其中$x,y,z$均为非负整数,表示2、3、5各出现的次数。
  • 若长度不超过1,则包含2、3、5三个素数的子序列个数为:$[1(2+1)(2+1)(2+1)]+[2(2+1)(2+1)(2+1)]+[3(2+1)(2+1)(2+1)]$,其中$[i]$表示$i$不超过K的整数。
  • 若长度不超过2,则包含2、3、5三个素数的子序列个数为:$[1(2+1)(2+1)(2+1)]+[2(2+1)(2+1)(2+1)]+[3(2+1)(2+1)(2+1)]+[4(2^2+2+1)(3^2+3+1)(5^2+5+1)]$。
  • ……
  • 若长度不超过K,则包含2、3、5三个素数的子序列个数为:$[1(2+1)(2+1)(2+1)]+[2(2+1)(2+1)(2+1)]+[3(2+1)(2+1)(2+1)]+ \cdots +[K(2^ {K-1}+2^{K-2}+\cdots+2+1)(3^{K-1}+3^{K-2}+\cdots+3+1)(5^{K-1}+5^{K-2}+\cdots+5+1)]$。

最后将上述的结果相加,就是所求的答案。

参考代码

以下是Python 3实现的代码片段:

def get_primes(n):
    """
    返回一个n以内的素数列表
    """
    is_prime = [True] * n
    primes = []
    for i in range(2, n):
        if is_prime[i]:
            primes.append(i)
            for j in range(i*i, n, i):
                is_prime[j] = False
    return primes


def count_subsequences(n, k):
    primes = get_primes(k+1)  # 获取小于等于k的素数列表
    res = 0
    # 计算包含不同素数的子序列个数
    for i in range(1, 1 << len(primes)):
        prod = 1
        for j in range(len(primes)):
            if i & (1 << j):
                prod *= primes[j]
        cnt = n // prod
        if cnt == 0:
            continue
        if bin(i).count("1") % 2 == 0:
            res -= cnt
        else:
            res += cnt
    # 计算长度不超过k的子序列个数
    for i in range(1, k+1):
        prod = 1
        for prime in primes:
            prod *= prime ** min(i, k // prime)
        res += (n // prod) * ((-1) ** (i+1))
    return res

其中,get_primes函数用于获取小于等于$k$的素数列表,count_subsequences函数用于计算包含不同素数的、长度不超过$k$的子序列个数。