codeforces 451E. Devu and Flowers 容斥原理+lucas

题目链接

给n个盒子, 每个盒子里面有f[i]个小球, 然后一共可以取sum个小球。问有多少种取法, 同一个盒子里的小球相同, 不同盒子的不同。

首先我们知道, n个盒子放sum个小球的方式一共有C(sum+n-1, n-1)种, 但是这个题, 因为每个盒子里的小球有上限, 所有用刚才那种方法不行。

但是我们可以枚举。 n只有20, 一共(1<<20)-1种状态, 每种状态, 1代表取这个盒子里的小球超过了上限, 0代表没有。

一共取sum个, 如果一个盒子里面的小球超过了上限, 那么就还剩下sum-f[i]-1个,因为可以为空, 所以要多减一。

然后就用容斥就可以了。

lucas定理, C(n, k)%mod p = C(n%p, k%p)*C(n/p, k/p)%mod p, 前面那部分可以直接算, 后面那部分继续lucas递归。

C(n, k)可以用乘法逆元算。

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-8;
const ll mod = 1e9+7;
const int inf = 1061109567;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
ll pow(ll a, ll b) {
    ll tmp = 1;
    while(b) {
        if(b&1LL) {
            tmp = tmp*a%mod;
        }
        a = (a*a)%mod;
        b>>=1LL;
    }
    return tmp;
}
ll C(ll a, ll b) {
    if(a<b) {
        return 0;
    }
    if(b>a-b) {
        b = a-b;
    }
    ll s1 = 1, s2 = 1;
    for(ll i = 0; i<b; i++) {
        s1 = s1*(a-i)%mod;
        s2 = s2*(i+1)%mod;
    }
    return s1*pow(s2, mod-2)%mod;
}
ll lucas(ll a, ll b) {
    if(b == 0)
        return 1;
    return C(a%mod, b%mod)*lucas(a/mod, b/mod)%mod;
}
ll a[22];
int main()
{
    int n, flag;
    ll s, sum, ans = 0;
    cin>>n>>s;
    for(int i = 0; i<n; i++) {
        scanf("%I64d", &a[i]);
    }
    for(int i = 0; i<(1<<n); i++) {
        sum = s, flag = 1;
        for(int j = 0; j<n; j++) {
            if(i&(1<<j)) {
                flag *= -1;
                sum = sum-a[j]-1;
            }
        }
        if(sum<0)
            continue;
        ll tmp = C((sum+n-1)%mod, n-1)%mod;
        ans = (ans+flag*tmp)%mod;
    }
    ans = (ans+mod)%mod;
    cout<<ans<<endl;
    return 0;
}

 

posted on 2016-02-24 15:50  yohaha  阅读(212)  评论(0编辑  收藏  举报

导航