[编程题]小Q的歌单 (python动态规划版)

链接:https://www.nowcoder.com/questionTerminal/f3ab6fe72af34b71a2fd1d83304cbbb3
来源:牛客网
 

[编程题]小Q的歌单

小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法。

 

输入描述:

每个输入包含一个测试用例。
每个测试用例的第一行包含一个整数,表示歌单的总长度K(1<=K<=1000)。
接下来的一行包含四个正整数,分别表示歌的第一种长度A(A<=10)和数量X(X<=100)以及歌的第二种长度B(B<=10)和数量Y(Y<=100)。保证A不等于B。


 

输出描述:

输出一个整数,表示组成歌单的方法取模。因为答案可能会很大,输出对1000000007取模的结果。

示例1

输入

5
2 3 3 3

输出

 

9

思路描述 

将所有的歌都放入一个数组length中,为了计算方便不会越界,应该在数组开头补一个0,故例子中3首长度为2,3首长度为3的数组就该建为length=[0,2,2,2,3,3,3].

再设置一个二维数组dp[][],并初始化为(目标长度+1)*(len(length)+1)。其中dp[ i ][ j ]代表歌曲列表中的前 j 个元素所包含的能够加起来达到长度 i 的组合数(每一个组合所包含歌曲的个数在0 ~ j之间)。

当i = 0时,dp[ i ][ j ]也就意味着前j首歌所包含的能够加起来达到长度0 的组合数,这个很显然是1,也就是所有的歌都不添加到和中,因此需要在一开始就把dp[ 0 ][ j ]置为1。

当i > 0, j = 0时,dp[ i ][ j ]的意思就是前0首歌所包含的能够加起来达到长度i 的组合数,这个显然是0,因为0首歌并不能达到 i>0的长度。

此时dp为(空白的地方才是dp)

 0222333
01111111
1       
2       
3       
4       
5       

若是 j >0:

  如果 length[j] >  i,那么第j首歌一定无法添加到任意组合中去,因为组合出的长度和已经大于 i 了,因此第 j 首歌的加入并不能使得前 j 个元素所包含的满足条件的组合数变多,因此 dp[ i ][ j ] = dp[ i ][ j - 1] ;  

  如果 length[j] = i , 那么第j首歌的加入能够使得前j个元素所包含的满足条件的组合数比前 j - 1首歌所包含的组合数多 1 ,多出来的1就是直接一个第 j首歌的长度刚好够了 i 。

  如果 length[j] < i, 那么第 j 首歌的加入也许能够使得前j 个元素所包含的满足条件的组合数增加,这个取决于 dp[ i - length[ j ] ][ j - 1 ],如果该值不为0,那么第j首歌加入之后这些组合加上第j首歌的长度刚好达到了i (就是 i - length[ j ] + length[ j ]) ,此时就要把两种情况的组合数相加: dp[ i ][ j ] = dp[ i ][ j - 1]  + dp[ i - length[ j ] ][ j - 1];  

dp最后的结果为

 0222333
01111111
10000000
20123333
30000123
40013333
50000369


 

import sys
if __name__ == "__main__":
    data=[]
while True:
    line = sys.stdin.readline().strip()
    if not line:
        break
    tmp = list(map(int, line.split(" ")))
    data.append(tmp)
n=data[0][0]
l=data[1]
length=[0]
for i in range(l[1]):
    length.append(l[0])
for i in range(l[-1]):
    length.append(l[-2])
def gedan(n,length):
    dp=[[0 for i in range(len(length))]for i in range(n+1)]
    for i in range(5):
        dp[0][i]=1
    for j in range(1,n+1):
        dp[j][0]=0
    for i in range(1,n+1):        
        for j in range(1,len(length)):
            if length[j] > i:
                dp[i][j] = dp[i][j-1] 
            elif length[j] == i:
                dp[i][j]=dp[i][j-1]+1
            else:
                dp[i][j] = dp[i][j-1]+dp[i-length[j]][j-1]                
    return dp[n][len(length)-1]%1000000007
print(gedan(n,length))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值