音乐列表

题目描述
小明喜欢在火车旅行的时候用手机听音乐,他有N首歌在手机里,在整个火车途中,他可以听P首歌,所以他想产生一个播放表产生P首歌曲,这个播放表的规则是:
(1)每首歌都要至少被播放一次
(2)在两首一样的歌中间,至少有M首其他的歌
小明在想有多少种不同的播放表可以产生,那么给你N,M,P,你来算一下,输出结果取1000000007的余数

输入描述:
输入N,M,P
N范围在1到100
M范围在0到N
P范围在N到100

输出描述:
输出结果mod 1000000007的余数

 1 import math
 2 n,m,p = map(int,input().split())
 3 dp = [[0 for _ in range(p+1)] for _ in range(n+1)]
 4 for i in range(m+1,n+1):
 5     for j in range(i,p+1):
 6         if j == i or i == m+1:
 7             dp[i][j] = math.factorial(i)
 8         else:
 9             dp[i][j] = dp[i-1][j-1] * i + dp[i][j-1] * (i-m)
10 print(dp[n][p]%1000000007)

算法思路:动态规划。

本题目要计算的是,用n首不同的歌曲组成一个长度为p的歌曲列表,有多少种可能。

其中有两个条件:

1每首歌曲至少要播放一次,那必定p>=n,否则本条件无法满足,这个条件是隐含的,容易被忽略;

2相同的两首歌中间,至少间隔m首其他的歌曲。

举一个实际的例子来说明本题目的思路。假设n=4,m=2,p=5。

定义dp[n+1][p+1]二维数组,初始值为0。每一个元素表示由i首歌组成长度为j的列表,有多少可能。显然dp[n][p]即为所求。

i=0,表示有0首歌,其值都为0,表示不可能组成歌单。

i=1,表示有1首歌,要分两种情况讨论:

  如果m=0,则值为1;如果m>=1,则值为0。本题m=2,因此值均为0。

i=2,表示有2首歌,

  如果m=0,则2*2=4;如果m=1,则2*1=2;如果m>=2,则值为0。本题m=2,因此值为0。

由以上分析可发现,从第0行到第m行的值均为0,那么只需要从第m+1行开始计算即可。见代码第4行:range(m+1,p+1)

i=3,表示有3首歌,本题m=2,

  j=3,第一个位置有3种选择,第二个位置有2种选择,第二个位置有1种选择。见代码第7行math.factorial()计算阶乘。

  j=4,要计算的是3首歌生成一个长度为4的歌单,把此问题分成两部分考虑:

    第一部分,2首歌生成长度为3的歌单,间隔2首。左上 * i

    第二部分,3首歌生成长度为3的歌单,间隔2首。左 * (i - m)

  结果为两部分之和。

但是为什么这样划分,我还没有想明白。只能先记录下来吧,也许以后能理解吧。

posted on 2019-08-09 14:08  Sempron2800+  阅读(203)  评论(0编辑  收藏  举报