小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 EatCho {
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int days = sc.nextInt();
int count = sc.nextInt();
if (days <= 1 || days > count){
System.out.println(count);
return;
}
//推測理想情況下,次日吃的數量都是前一天的1/2,則得到以下求第一天最大塊數公式:
//分子爲2的n次冪
//分母爲等比數列 a1 *(1-q的n次冪)/(1-q)
// int high = (int)(Math.pow(2, days-1)/ (Math.pow(2, days) - 1) * count);
// 最多第一天吃的塊數(因爲測試用例太大,導致上面的數學優化不能使用,只能從count-1開始)
int high = count-1;
int low = 1;//最少第一天吃1塊
int tar = high;
//採用折半查找
while (low <= high) {
int mid = (low + high)/2;
int sum = count - mid;//第二天起剩餘的塊數
int tmp = mid;
int i = 2;
for (; i <= days; i++){
tmp = (int)Math.ceil(tmp/2.0);//用於記錄今天最少吃的數量
sum -= tmp;
if (sum < 0){
//表明不夠吃了情況
break;
}
}
if (i < days)//供過於求
high = mid - 1;
else {
if (sum < 0)//供不應求
high = mid - 1;
else{
low = mid + 1;
tar = mid;
}
}
}
System.out.println(tar);
}
}