洛谷 CF295C Greg and Friends

题目来源于:洛谷

题目本质:模拟,动态规划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;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值