Luogu CF451E Devu and Flowers 题解报告

题目传送门

【题目大意】

有n种颜色的花,第i种颜色的花有a[i]朵,从这些花中选m朵出来,问有多少种方案?答案对109+7取模

【思路分析】

这是一个多重集的组合数问题,答案就是:$$C_{n+m-1}^{n-1}-\sum_{i=1}^{n}C_{n+m-a[i]-2}^{n-1}+\sum_{1\le i<j\le n}C_{n+m-a[i]-a[j]-3}^{n-1}-…+(-1)^nC_{n+m-\sum_{i=1}^{n}a[i]-(n+1)}^{n-1}$$

在具体实现的时候,我们可以枚举x=0~2n-1,若x在二进制表示下共有p位为1,分别是第i[1],i[2]…i[p]位,则这个x就代表上式中的这一项:$$(-1)^pC_{n+m-a[i[1]]-a[i[2]]-…-a[i[p]]-(p+1)}^{n-1}$$

这样我们就可以成功地得到容斥原理计算多重集组合数的公式的每一项。

【代码实现】

 #include<bits/stdc++.h>
#define ll long long
#define go(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
ll a[],m,ans=;
int inv[],n;
const int mod=1e9+;
int ksm(int x,int y){
int as=;
while(y){
if(y&) as=(ll)as*x%mod;
x=(ll)x*x%mod;
y>>=;
}
return as;
}
int C(ll y,int x){//计算组合数
if(y<||x<||x>y) return ;
y%=mod;
if(y==||x==) return ;
int as=;
go(i,,x-) as=(ll)as*(y-i)%mod;
go(i,,x) as=(ll)as*inv[i]%mod;
return as;
}
int main(){
go(i,,) inv[i]=ksm(i,mod-);//预处理逆元
scanf("%d%lld",&n,&m);
go(i,,n) scanf("%lld",&a[i]);
for(int x=;x<(<<n);x++){//枚举x
if(x==) ans=(ans+C(n+m-,n-))%mod;
else {
ll t=n+m;
int p=;
go(i,,n-)
if((x>>i)&) p++,t-=a[i+];
t-=p+;
if(p&) ans=(ans-C(t,n-))%mod;
else ans=(ans+C(t,n-))%mod;
}
}
cout<<(ans+mod)%mod<<endl;
return ;
}

代码戳这里

上一篇:C#字符串操作 取文本左边 取文本右边 取文本中间 取文本中间到List集合 指定文本倒序


下一篇:console 高级用法