CF451E Devu and Flowers

Desciption

求一个可重集 \(S\)\(m\) 子集的个数。\(S\) 的不同元素个数为 \(n\)\(n\leq 20\)。每种元素的个数 \(a_i\leq 10^{12}\) 。答案对 \(10^9+7\) 取模。

Solution

如果每种元素都有无数种的话,那么直接用插板法可得方案数为 \(\binom{m+n-1}{n-1}\)。但是问题是每种元素个数都有一个上界,这样会得到一些不合法的方案。考虑将其减去。令 \(f_{sta}\) 表示至少是元素集合为 \(sta\) 的所有元素都超上界的方案,其中 \(sta\) 是一个二进制状态,也是一个集合。那么有

\[f_{sta}=\binom{m+n-1-\sum_{i\in sta} (a_i+1)}{n-1} \]

再令 \(g_{sta}\) 表示恰好是集合 \(sta\) 里的元素超上界的方案,由容斥原理得

\[g(S)=\sum_{S\subseteq T} (-1)^{|T|-|S|} f(T) \]

我们要求的答案就是

\[g(\emptyset)=\sum_{T} (-1)^{|T|} f(T) \]

所以只需要快速求出 \(f(T)\)\(f(T)\) 中上标很大,但下标很小,所以中间约掉后,总共只需要算十几次。还要注意,如果直接将那几个大数乘在一起的话,即使是取模也会爆 long long,正确的做法是用 Lucas 定理将上标化小。

\[\binom{n}{m}\equiv \binom{n/p}{m/p} \times \binom{n \bmod p}{m \bmod p} \equiv \binom{n \bmod p}{m} \]

复杂度 \(O(n2^n)\)

#include<stdio.h>
#define ll long long

const int N=20;
const int Mod=1e9+7;

ll a[N],inv[23];

ll C(ll n,ll m){
    n%=Mod;
    if(n<m) return 0;
    ll ret=1;
    for(ll i=1;i<=m;i++) ret=ret*inv[i]%Mod;
    for(ll i=n-m+1;i<=n;i++) ret=ret*i%Mod;
    return ret;
}

int n;
ll ans=0,m;

void dfs(int st,int op,ll now){
    if(st==n){ans=(ans+op*C(now,n-1)%Mod+Mod)%Mod;return;}
    dfs(st+1,op,now); 
    if(now-a[st]-1<0) return;
    dfs(st+1,-op,now-a[st]-1);
}

int main(){
    scanf("%d%lld",&n,&m);
    for(int i=0;i<n;i++) scanf("%lld",&a[i]);
    inv[1]=1; for(int i=2;i<20;i++) inv[i]=(Mod-Mod/i)*inv[Mod%i]%Mod;
    dfs(0,1,n+m-1);
    printf("%lld",ans);
}
posted @ 2021-06-17 22:18  Kreap  阅读(41)  评论(0编辑  收藏  举报