首页 > 代码库 > UVALive 7143 Room Assignment(组合数学+DP)

UVALive 7143 Room Assignment(组合数学+DP)

题目链接

参考自:http://www.cnblogs.com/oyking/p/4508260.html

题意

n个人,其中有k对双胞胎.现有m间房间,每间房间有容量ci问分配房间的方案数。

 

分析

设dp[i][j]为已经放满了第i个房间之后,所剩下的双胞胎的对数还有j对,然后对于i+1间房,我们可以从剩余的j对中选择出a对,每对双胞胎只是放一个就好,然后又从j-a对双胞胎中选b对全部放进去,然后再从剩余的sum-j2中选择c[i]-a-2b个放进i+1个房间里面,这样的话就能得到转移方程,dp[i+1][j-a-b]=dp[i][j]C(j,a)C(j-a,b)C(sum-j2,c[i]-a-b2);然后组合数就用逆元去算就ok了。时间复杂度是O((mk)³)

 

#include <cstdio>#include <algorithm>#include <iostream>#include <cstring>using namespace std;typedef long long LL;const int MAXN = 100010;const int MOD = 1e9 + 7;int inv[MAXN], fact[MAXN];int _inv(int x) {    if(x == 1) return 1;    return LL(MOD - MOD / x) * _inv(MOD % x) % MOD;}void init(int n = 100000) {    fact[0] = 1;    for(int i = 1; i <= n; ++i)        fact[i] = fact[i - 1] * LL(i) % MOD;    for(int i = 0; i <= n; ++i)        inv[i] = _inv(fact[i]);}LL comb(int a, int b) {    if(a < b) return 0;    return LL(fact[a]) * inv[b] % MOD * LL(inv[a - b]) % MOD;}int dp[13][111];int c[13];int T, n, m, k;int mulmul(LL a, LL b, LL c, LL d) {    return a * b % MOD * c % MOD * d % MOD;}void update_add(int &a, int b) {    a += b;    if(a >= MOD) a -= MOD;}int solve() {    memset(dp, 0, sizeof(dp));    dp[0][k] = 1;    for(int i = 0, sum = n; i < m; ++i) {        for(int r = 0; r <= k; ++r) if(dp[i][r]) {            if(sum < 2 * r) break;            for(int a = 0; a <= r; ++a) {                for(int b = 0; b + a <= r; ++b) {                    if(c[i + 1] - a - 2 * b < 0) break;                    int t = mulmul(dp[i][r], comb(r, a), comb(r - a, b), comb(sum - 2 * r, c[i + 1] - a - 2 * b));                    update_add(dp[i + 1][r - a - b], t);                }                if(i == m - 1) break; /// if i = m - 1 then a must be zero            }        }        sum -= c[i + 1];    }    return dp[m][0];}int main() {    init();    //printf("%d\n", comb(10, 1));    scanf("%d", &T);    for(int t = 1; t <= T; ++t) {        scanf("%d%d%d", &n, &m, &k);        for(int i = 1; i <= m; ++i) scanf("%d", &c[i]);        printf("Case #%d: %d\n", t, solve());    }}

 

UVALive 7143 Room Assignment(组合数学+DP)