2018腾讯春招
背包问题
题目描述: 小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
**分析:**这道题目难点在求组合的那里,数据会非常的大,所以可以借助杨辉三角来做。
#include <iostream>
using namespace std;
long long arr[101][101];
void init() {
// 创建一个杨辉三角如下:
// 1
// 1 2 1
// 1 3 3 1
// 1 4 6 4 1
// 1 5 10 10 5 1
// 根据数学的归纳公式:c(n, k) = c(n-1, k-1) + c(n - 1, k).
for (int i = 0; i < 101; i++)
for (int j = 0; j < 101; j++)
arr[i][j] = 0;
arr[0][0] = 1;
for (int i = 1; i < 101; i++) {
arr[i][0] = 1;
for (int j = 1; j < 101; j++) {
arr[i][j] = (arr[i - 1][j - 1] + arr[i - 1][j]) % 1000000007;
}
}
}
int main() {
init();
int k, a, x, b, y;
scanf("%d%d%d%d%d", &k, &a, &x, &b, &y);
long long sum = 0;
for (int i = 0; i <= x; i++) {
for (int j = 0; j <= y; j++) {
if (a != b) {
if ((a * i + b * j) == k) {
sum += (arr[x][i] * arr[y][j]);
} else if ((a * i + b * j) > k) {
break;
}
}
}
}
cout << sum % 1000000007 << endl;
return 0;
}