[编程题]小Q的歌单(动态规划)
链接:https://www.nowcoder.com/questionTerminal/f3ab6fe72af34b71a2fd1d83304cbbb3
来源:牛客网
问题描述:
小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
解决思路:
1. 用数组dp来存储结果,dp[i][j]表示用前j首歌表示长度为i的歌单的方法数,i=1…K,j=1,…,na+nb。na是第1种歌的数量,nb是第2种歌的数量
2. lens[j]表示第j首歌的长度,如果i>=lens[j],那么由前j首歌组成长度为i的歌单的方法数可分为两部分,第一部分是dp[i][j-1],即由前j-1首歌组成长度
为i的歌单的方法数,第二部分是dp[i-lens[j]][j-1],即由j-1首歌组成长度为i-lens[j]的歌单的方法数,因为第j首歌已经占据了lens[j]的长度。
3. 如果i<lens[j]i<lens[j],那么dp[i][j][i][j]等于dp[i][j−1][i][j−1]。
代码:
#include <iostream> #include <algorithm> #include<string.h> #include<map> #include<iterator> #include<math.h> using namespace std; const int mod =1000000007; int k; int a,x,b,y; int dp[1010][210]; int len[210]; int main() { cin>>k; cin>>a>>x>>b>>y; int length=x+y; memset(dp,0,sizeof(dp)); memset(len,0,sizeof(len)); dp[0][0]=1; for(int i=1;i<=x;i++) len[i]=a; for(int i=x+1;i<=length;i++) len[i]=b; for(int i=0;i<=k;i++) for(int j=1;j<=length;j++) { if(i>=len[j]) { dp[i][j]=(dp[i][j-1]+dp[i-len[j]][j-1])%mod; } else { dp[i][j]=dp[i][j-1]%mod; } } cout<<dp[k][length]<<endl; return 0; }