鏈接: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; }