小Q的歌單_騰訊2018春招技術類程式設計題
[程式設計題] 小Q的歌單
時間限制: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
輸出例子1:
9
程式碼
import java.util.Scanner; public class Main{ public static long[][] arr = new long[101][101]; public static void main(String[] args){ Scanner scan = new Scanner(System.in); int k = scan.nextInt(); int A = scan.nextInt(); int X = scan.nextInt(); int B = scan.nextInt(); int Y = scan.nextInt(); Initial(arr); System.out.println(Calculate(k,A,X,B,Y)); } public static void Initial(long[][] array){ array[0][0] = 1; for(int i = 1;i <= 100;i++){ array[i][0] = 1; for(int j = 1;j <= 100;j++){ array[i][j] =( array[i-1][j-1] + array[i-1][j])%1000000007;; } } } public static long Calculate(int K, int A, int X, int B, int Y){ long result = 0; int length; for (int i = 0; i <= X; i++){ length = K - A * i; if (length >= 0 && length % B == 0 && length / B <= Y){ result += (arr[X][i] * arr[Y][length / B])% 1000000007; } } return result % 1000000007; } }
提交結果
您的程式碼已儲存
答案正確:恭喜!您提交的程式通過了所有的測試用例
解題思路
由於不需要考慮歌單內歌曲的先後順序,且每首歌只能出現一次,則該問題可以看成以下取多少種歌曲組合最後組成某個長度的歌單,歌曲之間相互獨立。比如需要組合的歌單長為5,現有3首歌曲長度為2和3首歌曲長度為3的不同歌曲,可以選取1首歌曲長度為2的歌曲和1首歌曲長度為3的歌曲,歌曲長度為2的歌曲可以選擇的物件有3種,歌曲長度為3的歌曲可供選擇的物件也為3種,3乘以3得9,故組合的歌單種類為9種。
利用暴力迴圈求得所有歌單長度的組合方法,假設選取A類歌曲的個數從0到最大值,然後根據這個A類歌曲選取值選取求得B類歌曲選取個數,注意並不一定所有A類歌曲的選擇個數都可以恰好組合成歌單,判斷條件是選取的B類歌曲個數恰好為整數,且不大於B類歌曲個數最大值。
剩下的問題就是求得從M個不同小球中取得N個小球的組合數,在數學中可以記作為 ,由於最後得數的數量級有點大,在一開始的時候遇到了點問題,利用數學中常見方式求得該組合數值無法得出正確的測試結果,當M=10,N=4時,計算方法是result = 10*9*8*7/(4*3*2*1),該方法在是沒有問題但最後ACE的結果老無法得到正確結果。最後分析原因,是因為題目中要求輸出對1000000007取模的結果。
public static long calculate(long x,long i){
long mod = 1000000007;
long result = 1;
if(i > (x/2))
i = x-i;
if(x < i){
return 0;
}else if(x == i){
return 1;
}else {
for(long k = 1;k <= i;k++){
result = (result * (x - k + 1) / k)%mod;
System.out.println(result);
}
return result/mod;
}
}
當乘積的結果不是很大的時候以上程式碼計算值是符合題目要求的,但是一旦超過long的範圍輸出值則不符合要求,被乘數每次取模必然是不對的,只有通過加法求得各種組合數才是符合題目要求的,參見正確程式碼中Initial函式。使用相乘法求組合數最大的ace正確率只能達到70%。
通過加法求解組合數是01揹包問題,這裡就不再概述了。