网易笔试——小易喜欢的数列

网易笔试——小易喜欢的数列
题目

小易非常喜欢拥有以下性质的数列:
1、数列的长度为n
2、数列中的每个数都在1到k之间(包括1和k)
3、对于位置相邻的两个数A和B(A在B前),都满足(A <= B)或(A mod B != 0)(满足其一即可)
当n = 4, k = 7时,那么对于{1,7,7,2},它的长度是4,所有数字也在1到7范围内,并且满足第三条性质,所以小易喜欢这个数列。
但是小易不喜欢{4,4,4,2}这个数列。小易给出n和k,希望你能帮他求出有多少个是他会喜欢的数列。

输入

多组输入,每组输入包括n和k

输出

输出满足题意的数列个数,将总数对1000000007取模

思路
  1. 首先考虑数列长度=1的情况。n=1时,数列只有一位,那么这一位数可以取1,…,k中任意一种,此时满足题意的数列总数为k。

  2. 再考虑数列长度=2的情况。n=2的数列就是在n=1的满足题意的数列后再加上一位数(我们把n=1末位的数叫A,新加的这位数则是B),B在1,…,k中选取且要A与B满足条件3。显然,对于 B = i ( i = 1 , . . . , k ) B=i(i=1,...,k) B=i(i=1,...,k)的每一种情况,有
    长度为 2 , B 取 i 且满足题意的数列数 = n 为 1 且满足题意的数列数 − B 与 A 不满足条件 3 的数列数 = k − B 与 A 不满足条件 3 的数列数 长度为2,B取i且满足题意的数列数\\=n为1且满足题意的数列数-B与A不满足条件3的数列数\\=k-B与A不满足条件3的数列数 长度为2,Bi且满足题意的数列数=n1且满足题意的数列数BA不满足条件3的数列数=kBA不满足条件3的数列数
    那么长度为2且满足题意的数列数就是把 B = i B=i B=i的每一种情况加起来。
    长度为 2 且满足题意的数列数 = ∑ B = 1 k ( k − B 与 A 不满足条件 3 的数列数 ) 长度为2且满足题意的数列数=\sum_{B=1}^k (k-B与A不满足条件3的数列数) 长度为2且满足题意的数列数=B=1k(kBA不满足条件3的数列数)

  3. 到这里看出来这是一个动态规划问题,长度为i的数列数是可以由子问题——长度为i-1的数列数计算而来的。设 d p [ i ] [ j ] dp[i][j] dp[i][j]——长度为 i i i且第 i i i位数为 j j j的满足题意的数列总数

  4. 考虑数列长度=i-1的情况,设数列的第i-1位数为 A ( A = 1 , . . . , k ) A(A=1,...,k) A(A=1,...,k)。那么

长度为 i − 1 且满足题意的数列数 = ∑ j = 1 k d p [ i − 1 ] [ j ] 长度为i-1且满足题意的数列数=\sum_{j=1}^k dp[i-1][j] 长度为i1且满足题意的数列数=j=1kdp[i1][j]

  1. 考虑数列长度=i的情况,显然这是在长度为i-1的数列后新加一位数,设新加的这位数为 B B B。要满足题意必须保证 A A A B B B满足条件3,因此对于 B = j ( j = 1 , . . . , k ) B=j(j=1,...,k) B=j(j=1,...,k)的每一种情况,有(由4, A = j A=j A=j
    长度为 i , B 取 j 且满足题意的数列数 = d p [ i ] [ j ] = 长度 i − 1 的数列数 − B 与 A 不满足条件 3 的数列数 = ( ∑ A = 1 k d p [ i − 1 ] [ A ] ) − B 与 A 不满足条件 3 的数列数 = ∑ A = 1 k i f ( A % j ! = 0 ∣ ∣ A ≤ j ) d p [ i − 1 ] [ A ] 长度为i,B取j且满足题意的数列数=dp[i][j]\\=长度i-1的数列数-B与A不满足条件3的数列数\\=(\sum_{A=1}^k dp[i-1][A])-B与A不满足条件3的数列数\\ =\sum_{A=1}^k if(A\%j!=0||A\leq j)dp[i-1][A] 长度为i,Bj且满足题意的数列数=dp[i][j]=长度i1的数列数BA不满足条件3的数列数=(A=1kdp[i1][A])BA不满足条件3的数列数=A=1kif(A%j!=0∣∣Aj)dp[i1][A]

上式第3行即状态转移方程:
d p [ i ] [ j ] = ∑ A = 1 k i f ( A % j ! = 0 ∣ ∣ A ≤ j ) d p [ i − 1 ] [ A ] \begin{aligned} dp[i][j]=\sum_{A=1}^k if(A\%j!=0||A\leq j)dp[i-1][A] \end{aligned} dp[i][j]=A=1kif(A%j!=0∣∣Aj)dp[i1][A]
一般地,对于长度为 i i i的数列,其满足题意的数目如下式:
长度为 i 且满足题意的数列数 = ∑ j = 1 k d p [ i ] [ j ] \begin{equation} 长度为i且满足题意的数列数=\sum_{j=1}^k dp[i][j] \end{equation} 长度为i且满足题意的数列数=j=1kdp[i][j]

import sys

global max_k,mod
max_k = 1e5+5
mod = 1000000007

"""dp[i][j]——在由i个数字组成的数列中,第i位数为j的被小易喜欢的数列"""

for line in sys.stdin:
    a = line.split()
    n = int(a[0])
    k = int(a[1])

    # dp数组初始化
    dp = [([0]*(k+1))for i in range(0, n+1)]
    for j in range(1, k+1):
        dp[1][j] = 1 #在由1位数字组成的数列中,第1位数位j的且符合题意的数列一定只有一种
	
	#状态转移
    for i in range(2, n+1): #分别遍历由2,...,n位数字组成的数列

        # 计算由i-1位数字组成的所有数列的总数
        all = 0 #all存储由i-1位组成的所有数列的总数
        for j in range(1, k+1):
            all += dp[i-1][j]

        for j in range(1, k+1):
            dp[i][j] = all
            #将dp[i][j]减去由i-1位数字组成且第i-1位的数字为j的倍数的数列
            p = 2*j
            while p <= k: #p是j的倍数且p<=k
                dp[i][j] -= dp[i-1][p]
                p += j
            dp[i][j] %= mod

    #计算最终结果
    result = 0
    for j in range(1, k+1):
        result += dp[n][j]
    result %= mod
    print(result)

参考题解:https://www.cnblogs.com/peterleee/p/10851821.html
https://www.freesion.com/article/3332778970/。

你可能感兴趣的:(牛客网,算法,数据结构,python,动态规划)