UESTC cdoj 619 吴神,人类的希望 (组合数学)

枚举盒子的个数,先把总数n减去掉box*k保证每个盒子至少有k个小球,剩下的小球放入盒子中可以为空,

加入box个小球保证每个盒子至少有一个小球,问题转化成不可区分小球放入不可区分盒子非空的方案数。

C[i][j]表示i个小球放入j个盒子非空的方案数,那么C[i][j] = C[i-1][j-1]+C[i-j][j],

分类:1.第j个盒子是空的,第i个小球必须放到第j个盒子中。

2.第j个盒子非空,第i个小球选一个盒子放,为了排除重复,我们注意到之前的盒子只有1层(最后一个盒子只放了一个小球),

那么先放一层减去j个小球,剩下i-j个往j个盒子里放,然后每个盒子都加一个小球,如果合法,那么至少会有2层。

对于可空的盒子,只要 把C[i-1][j-1]改成C[i][j-1]

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
const int maxn = 1001;
int C[maxn][maxn];

void GetC()
{
    for(int i = 0; i < maxn; i++){
        C[i][1] = C[i][i] = 1;
        for(int j = 1; j < i; j++){
            C[i][j] = (C[i-1][j-1]+C[i-j][j])%mod;
        }
    }
}

int main()
{
    GetC();
    int T; scanf("%d",&T);
    while(T--){
        int n,k; scanf("%d%d",&n,&k);
        int ans = 0;
        for(int box = 1,M = n/k; box <= M; box++){
            ans = (ans + C[n-box*k+box][box])%mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2015-08-24 13:26  陈瑞宇  阅读(226)  评论(0编辑  收藏  举报