这题想清楚就不难了hh,下面讲讲思路.
题目:给你n堆花的数量ai,要你从n堆花里选取m朵.问你有多少种选法?(这样当然不能重复hh).
怎么想呢?假设没有我们把m朵花铺平,且加n个隔板.
总方案数是多少?显然C(n+m,n).
不合法的方案数是多少?这个就要用容斥原理了,C(n+m-(ai+1),n).很简单吧hhh
然后我们用二进制枚举就gg了.然后由于容斥原理是有公式的,奇减偶加...emmm真的没了~
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const ll N=25; //组合数 ll qp(ll aa,ll bb) { ll res=1; aa%=mod; while(bb) { if(bb&1) res=res*aa%mod; aa=aa*aa%mod; bb>>=1; } return res; } ll C(ll n,ll m) { if(m>n) return 0; if(n-m<m) m=n-m; ll res=1; for(ll i=n;i>n-m;i--) { res=res*(i%mod)%mod; }ll sum=1; for(ll i=m;i>=2;i--) { sum=sum*i%mod; }ll lv=qp(sum,mod-2); return res*lv%mod; } //主函数代码实现 ll a[N]; int main() { ll n,m,ans=0; cin>>n>>m; for(ll i=0;i<n;i++) cin>>a[i]; for(ll i=0;i<(1<<n);i++)//枚举i表示选或不选当前数,假如选的为奇数就减,偶数就加. { ll cnt=0;ll pos=0; for(ll j=0;j<n;j++) { if(i>>j&1)//假如这一位有. { cnt++; pos=(pos+(a[j]+1))%mod; } } if(cnt%2==1)//奇数 { ans=(ans-C(n+m-1-pos,n-1)+mod)%mod; } else ans=(ans+C(n+m-1-pos,n-1))%mod; } cout<<ans<<endl; return 0; }