有n种物品,要取m个出来,如果每种物品的数量没有限制,答案为C(m,m+n-1)---多重集的计数
1.现在限制,某种物品大于x,解决方法是,m-=x 后 又按原来的方法解决
2.限制 ,物品a1小于x1,a2小于x2,……
转化为容斥问题
容斥原理附上两种写法
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define ll long long #define mod 100000007 ll pow_mod(ll a,ll b) { ll res=1; while(b) { if(b&1) res=(res*a)%mod; b>>=1; a=(a*a)%mod; } return res; } ll comb(ll n,ll m) { if(n<0 || m<0 || m>n) return 0; ll up=1,down=1; for(ll i=n;i>n-m;--i) up=(up*i)%mod; for(ll i=1;i<=m;++i) down=(down*i)%mod; ll res=up*pow_mod(down,mod-2)%mod; return res; } int a[50],cnt; ll dfs(int cur,ll down,ll up) { ll res=0; for(int i=cur;i<cnt;++i) { res += comb(down-a[i],up); res -= dfs(i+1,down-a[i],up); } return res; } ll n,m; char s1[1000],s2[1000],str[1000]; int main () { while(scanf("%lld%lld",&n,&m)!=EOF) { if(n==0) break; cnt=0; int num; gets(str); bool flag=true; while(1) { if(!gets(str)) break; if(strlen(str)<2) break; sscanf(str,"%s%s%s%d",s1,s1,s2,&num); if(s1[0]=='g') { m-=num+1; // greater than or equal to num+1 } else { // <num a[cnt++]=num; if(num==0) // less than 0, impossible flag=false; } } if(flag) { /*ll ans=comb(n+m-1,n-1)-dfs(0,n+m-1,n-1); ans=(ans%mod+mod)%mod;*/ ll ans=comb(n+m-1,n-1); int tot=(1<<cnt)-1; for(int i=1;i<=tot;++i) // 二进制枚举出 2^(cnt)个状态 { int ones=0; ll temp=0; for(int j=0;j<cnt;++j) if((i>>j)&1) { temp+=a[j]; ones++; } if(ones&1) ans=(ans-comb(n+m-1-temp,n-1))%mod; else ans=(ans+comb(n+m-1-temp,n-1))%mod; } ans=(ans%mod+mod)%mod; printf("%lld\n",ans); } else printf("0\n"); } return 0; }