题目描述:
Devu想用花去装饰他的花园,他已经购买了n个箱子,第i个箱子有fi朵花,在同一个的箱子里的所有花是同种颜色的(所以它们没有任何其他特 征)。另外,不存在两个箱子中的花是相同颜色的。 现在Devu想从这些箱子里选择s朵花去装饰他的花园,Devu想要知道,总共有多少种方式从这些箱子里取出这么多的花?因为结果有可能会很大,结果需要 对1000000007取模。 Devu认为至少有一个箱子中选择的花的数量不同才是两种不同的方案。
题解:
乍一看很难,但是化成容斥将会非常好做。
由于n极小,所以可以枚举每一篮子花是否超出当前fi,然后通过容斥有:
ans = g0 - g1 + g2 - g3 + g4 - g5 +……
其中gi表示有i个篮子超限时方式总数。
一定要多取余:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define MOD 1000000007 ll n; ll s,a[25],ans; ll fast(ll x,int y) { ll ret = 1ll; while(y) { if(y&1)ret=ret*x%MOD; x=x*x%MOD; y>>=1; } return ret; } ll C(ll x,ll y) { ll sx=1ll,sy=1ll; for(ll i=1ll;i<=y;i++) { sx=(sx*(x%MOD-i%MOD+1ll)%MOD+MOD)%MOD; sy=sy*(i%MOD)%MOD; } return (fast(sy,MOD-2)*sx%MOD+MOD)%MOD; } int main() { scanf("%lld%lld",&n,&s); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(int i=0;i<(1<<n);i++) { ll f=1ll,g=s; for(int j=0;j<n;j++) { if(i&(1<<j)) { g-=a[j+1]+1ll; f*=-1; } } if(g<0)continue; ans=((ans+f*C(g+n-1ll,n-1ll)%MOD)%MOD+MOD)%MOD; } printf("%lld ",ans); return 0; }