标签:10 盒子 多重集 ll 容斥 long acwing214 ans mod
题目链接: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
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。