题目来源于:洛谷
题目本质:模拟,动态规划dp,枚举
题目思路:
dp[i][j][k]表示第i次运送后对岸有j个50kg,k个100kg的方案数
若经过2*n次运送后则必为无解
状态转移方程:
dp[now][num1 - x + i][num2 - y + j] += dp[old][x][y] * c[x][i] % MOD * c[y][j] % MOD;
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
long long n, k;
long long a[55];
long long c[55][55];
long long dp[105][55][55];
long long num1, num2;
long long old, now;
bool ok;
int main() {
for(int i = 0; i < 50; i++) {
c[i][0] = 1;
for(int j = 1; j <= i; j++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
}
scanf("%lld%lld", &n, &k);
k /= 50;
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
if(a[i] == 50)
num1++;
else
num2++;
}
old = 1;
now = 0;
dp[0][num1][num2] = 1;
for(int l = 0; l < 2 * n; l++) {
swap(now, old);
memset(dp[now], 0, sizeof(dp[now]));
for(int i = 0; i <= num1; i++) {
for(int j = 0; j <= num2; j++) {
if(i + j * 2 && (i + j * 2) <= k) {
for(int x = i; x <= num1; x++) {
for(int y = j; y <= num2; y++) {
dp[now][num1 - x + i][num2 - y + j] += dp[old][x][y] * c[x][i] % MOD * c[y][j] % MOD;
}
}
}
}
}
if(dp[now][num1][num2]) {
printf("%d\n", l * 2 + 1);
printf("%lld\n", dp[now][num1][num2] % MOD);
ok = 1;
break;
}
swap(now, old);
memset(dp[now], 0, sizeof(dp[now]));
for(int i = 0; i <= num1; i++) {
for(int j = 0; j <= num2; j++) {
if(i + j * 2 && (i + j * 2) <= k) {
for(int x = i; x <= num1; x++) {
for(int y = j; y <= num2; y++) {
dp[now][num1 - x + i][num2 - y + j] += dp[old][x][y] * c[x][i] % MOD * c[y][j] % MOD;
}
}
}
}
}
}
if(ok == 0)
printf("-1\n0");
return 0;
}