题意:给N个数(a1,a2……an)和一个S,求(b1+b2+……+bn)==S的方案数,其中0<=bi<=ai;
分析:题意很简单,考虑容斥。
其中U为全集,t为U的i元组。
由于N<=20,直接二进制枚举即可,s很大,考虑使用lucas优化。
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
long long f[30];
long long qk(long long a,long long n)
{
long long ans=1;
while(n){
if(n&1)ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
long long c(long long a,long long b)
{
if(a==b)return 1;
if(a<b)return 0;
long long up=1,dw=1;
for (int i = a-b+1; i <= a; ++i) {
up=up*i%mod;
}
for (int i = 2; i <= b; ++i) {
dw=dw*i%mod;
}
return up*qk(dw,mod-2)%mod;
}
long long lucas(long long a,long long b)
{
if(a<mod&&b<mod)
{
return c(a,b);
}
else
{
return (c(a%mod,b%mod)*lucas(a/mod,b/mod))%mod;
}
}
int main () {
long long n,s;
long long ans=1;
cin>>n>>s;
for (int i = 0; i < n; ++i) {
scanf("%lld",&f[i]);
}
ans=lucas(s+n-1,n-1);//总方案数
int len=1<<n;
//二进制枚举,减去不合法方案
for (int i = 1; i < len; ++i) {
long long sum=0;
long long cnt=0;
for (int j = 0; j < n; ++j) {
int x=1<<j;
if(x&i)
{
cnt++;
sum+=f[j]+1;
}
}
if(cnt&1)
{
ans=(ans-lucas(s-sum+n-1,n-1)+mod)%mod;
}
else
{
ans=(ans+lucas(s-sum+n-1,n-1))%mod;
}
}
printf("%lld\n",ans);
}