有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;
}