其他分享
首页 > 其他分享> > 【CF451E】Devu and Flowers

【CF451E】Devu and Flowers

作者:互联网

题目大意:求多重集合的组合数, \(N \le 1e14,M \le 20\)。

题解:
考虑容斥原理,具体做法是枚举所有情况,即:枚举子集,第 i 位为 1 表示满足第 i 个条件,正负号采用 sign 进行判断。
对于本题的组合数来说,上指标过大,导致没办法预处理阶乘和逆元进行快速回答,不过下指标很小,可以按照定义进行枚举计算。

代码如下

#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long LL;
LL fpow(LL a,LL b,LL c){
    LL ret=1%c;
    for(;b;b>>=1,a=a*a%c)if(b&1)ret=ret*a%c;
    return ret;
}
LL C(LL n,LL m){
    if(n<m)return 0;
    m=min(m,n-m);
    LL ret=1,up=1,down=1;
    for(int i=1;i<=m;i++){
        up=up*(n-i+1)%mod;
        down=down*i%mod;
    }
    down=fpow(down,mod-2,mod);
    ret=ret*up%mod*down%mod;
    return ret;
}
LL Lucas(LL n,LL m){
    if(n<mod&&m<mod)return C(n,m);
    return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
}

LL f[21],s,ans;
int n;

int main(){
    scanf("%d%lld",&n,&s);
    for(int i=1;i<=n;i++){
        scanf("%lld",&f[i]);
    }
    
    for(int i=0;i<1<<n;i++){
        LL tot=s,sign=1;
        for(int j=1;j<=n;j++)
            if(i>>(j-1)&1){
                tot-=(f[j]+1);
                sign=-sign;
            }
        if(tot<0)continue;
        ans=(ans+Lucas(tot+n-1,n-1)*sign)%mod;
    }
    printf("%lld\n",(ans+mod)%mod);
    
    return 0;
} 

标签:CF451E,le,LL,ret,sign,枚举,tot,Devu,Flowers
来源: https://www.cnblogs.com/wzj-xhjbk/p/10979082.html