騰訊校招筆試題之小Q的歌單
阿新 • • 發佈:2018-12-26
題目
小Q的歌單
熱度指數:1624 時間限制:1秒 空間限制:32768K
小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
解答
一開始想用暴力求解來做,提交之後發現執行時間超過限制,只通過了60%的test cases。後來想到了動態規劃,這應該是一道很典型的動態規劃題目,具體思路如下。
思路
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. 如果 ,那麼dp等於dp。
程式碼
#include<iostream>
#include<stdlib.h>
#include <math.h>
using namespace std;
int main()
{
int i, j, K, la, lb, na, nb,result;
cin >> K;
cin >> la >> na >> lb >> nb;
if (K <= 0 || la <= 0 || na <= 0 || lb <= 0 || nb <= 0)
{
cout << "error!";
return 0;
}
int* lens = new int[na+nb+1];
for (i = 1; i <= na; i++)
{
lens[i] = la;
}
for (i = 1; i <= nb; i++)
{
lens[i+na] = lb;
}
int** dp= new int*[K+1];
for (i = 0; i < K + 1; i++)
{
dp[i] = new int[na + nb + 1];
}
for (j = 0; j < na + nb + 1; j++)
{
dp[0][j] = 1;
}
for (i = 1; i <= K ; i++)
{
if (lens[1] != i)
{
dp[i][1] = 0;
}
else
{
dp[i][1] = 1;
}
}
for (i = 1; i <= K; i++)
{
for (j = 2; j < na + nb + 1; j++)
{
if (i >= lens[j])
{
dp[i][j] = (dp[i][j-1]+dp[i-lens[j]][j-1]) % 1000000007;
//dp[i][j] = (dp[i][j - 1] + dp[i - lens[j]][j - 1]);
}
else
{
dp[i][j] = dp[i][j - 1] % 1000000007;
}
}
}
cout << dp[K][na+nb] << endl;
system("pause");
return 0;
}