cf451E Devu and Flowers 卢卡斯定理+容斥定理

来源:互联网 发布:网络交换机与PLC通讯 编辑:程序博客网 时间:2024/04/28 09:18

题目:http://codeforces.com/problemset/problem/451/E

题意:有n个盒子(n<=20),每个盒子中有10^12个小球,现从每个盒子中取出若干球(可为0),求共取出s个小球(s<=10^14)的方案数。


组合数学问题,求C(n,m).但n,m过大时,可用卢卡斯定理.

卢卡斯定理:C(n,m) %p = C(n/p,m/p) * C(n%p,m%p)


从n个盒子中取出s个球的方案数,相当于插板,即 C(s+n-1,n-1).注意这是没有限制条件的情况。

还要考虑哪些盒子取超了。

违法情况和 = 1个盒子取超的情况数 - 2个的 + 3个的 ....(容斥定理)

然后拿总方案数减去违法的,就是最终结果。总方案数 = C(s+n-1,n-1)


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<set>#include<cmath>using namespace std;typedef long long ll;const int N = 1e5+10;const ll mod = 1e9+7;const ll MOD = 1e9+7;ll k_pow(ll a,ll n,ll p){    ll ans = 1ll, mo = a;    while(n){        if(n&1) ans = (ans * mo)%p;        mo = (mo * mo)%p;        n /= 2;    }    return ans;}ll cal(ll n,ll m,ll p){    if(m>n) return 0;    ll ans = 1ll;    ll wt = 1ll;    if(m>n-m) m = n-m;    for(int i=1;i<=m;i++){        ans = (ans * (n-i+1))%p;        wt = (wt * i)%p;    }    wt = k_pow(wt,p-2,p);    ans = (ans * wt)%p;    return ans;}ll lucas(ll n,ll m,ll p){    if(m==0) return 1;    return ( lucas(n/p,m/p,p) * cal(n%p,m%p,MOD) )%p;}int n;ll s,f[30];int main(){    while(scanf("%d%I64d",&n,&s)!=EOF){        ll sum = 0;        for(int i=0;i<n;i++){            scanf("%I64d",&f[i]);            sum += f[i];        }        ll ans = 0;        for(int st=0;st<(1<<n);st++){            int fl = 1;            ll ts = s;            for(int i=0;i<n;i++) if((1<<i)&st){                fl *= -1;                ts -= f[i]+1;            }            if(ts<0) continue;            ans = (ans + fl*lucas(ts+n-1,n-1,MOD))%MOD;        }        ans = (ans + MOD)%MOD;        cout<<ans<<endl;    }    return 0;}


0 0
原创粉丝点击