acwing214 Devu和鲜花 多重集组合数,容斥,卢卡斯定理
作者:互联网
题目链接:https://www.acwing.com/problem/content/216/
Devu有N个盒子,第i个盒子中有Ai枝花。
同一个盒子内的花颜色相同,不同盒子内的花颜色不同。
Devu要从这些盒子中选出M枝花组成一束,求共有多少种方案。
若两束花每种颜色的花的数量都相同,则认为这两束花是相同的方案。
结果需对10^9+7取模之后方可输出。
输入格式
第一行包含两个整数N和M。
第二行包含N个空格隔开的整数,表示A1,A2,…,AN。
输出格式
输出一个整数,表示方案数量对10^9+7取模后的结果。
数据范围
1≤N≤20,
0≤M≤10^14,
0≤Ai≤10^12
输入样例:
3 5
1 3 2
输出样例:
3
题解:
参考李煜东大佬的算法竞赛进阶指南。
算组合数的时候m较大,n较小。 C(n+m-1,n-1)=n! / (n!(n-m)!) =((n+m-1)*(n+m-2)*...(m+1) /(1*2*...(n-1))
可以先算出((n+m-1)*(n+m-2)*...(m+1),然后乘(n-1)!的逆元。
可以用卢卡斯定理,先对n+m-1 对1e9+7取模,再计算组合数,就不会超出long long 范围
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll a[22],ni[22];
ll ksm(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
ll C(ll y,ll x){
if(x<0||y<0||y<x) return 0;
y%=mod;
ll ans=1;
for(int i=y-x+1;i<=y;i++) ans=ans*i%mod;
for(int i=1;i<=x;i++) ans=ans*ni[i]%mod;
return ans;
}
void init(){
for(int i=1;i<=20;i++) ni[i]=ksm(i,mod-2);
}
int main(){
init();
ll n,m;
cin>>n>>m;
for(int i=0;i<n;i++) scanf("%lld",&a[i]);
ll ans=C(n+m-1,n-1);
for(int i=1;i<(1<<n);i++){
ll t=n+m;
int p=0;
for(int j=0;j<n;j++){
if(i>>j&1){
p++;
t-=a[j];
}
}
t-=(p+1);
if(p&1) ans=(ans-C(t,n-1)+mod)%mod;
else ans=(ans+C(t,n-1))%mod;
}
printf("%lld\n",ans);
return 0;
}
标签:10,盒子,多重集,ll,容斥,long,acwing214,ans,mod 来源: https://blog.csdn.net/weixin_42757232/article/details/100056764