题目:Devu and Flowers
题意:
有n个花坛,要选s支花,每个花坛有f[i]支花,同一个花坛的花颜色相同,不同花坛的花颜色不同,问可以有多少种组合。
解析:
多重集组合数+
L
u
c
a
s
Lucas
Lucas定理+状压。
直接上多重集组合数的公式就行了,这里由于
n
≤
  
20
n\leq\;20
n≤20,可以将状态压缩为二进制数,即枚举
x
=
0
x=0
x=0~
2
n
−
1
2^n-1
2n−1,若
x
x
x在二进制表示下共有
p
p
p位为1,分别是第
i
1
,
i
2
,
.
.
.
.
.
.
i
p
i_1,i_2,......i_p
i1,i2,......ip位,则这个
x
x
x就代表公式中的
(
−
1
)
p
C
N
+
M
−
c
i
1
−
c
i
2
−
.
.
.
.
.
.
−
c
i
p
−
p
−
1
N
−
1
(-1)^pC_{N+M-c_{i_1}-c_{i_2}-......-c_{i_p}-p-1}^{N-1}
(−1)pCN+M−ci1−ci2−......−cip−p−1N−1
特别的,若
x
=
0
x=0
x=0则代表
C
N
+
M
−
1
N
−
1
C_{N+M-1}^{N-1}
CN+M−1N−1。并且为了防止爆
l
o
n
g
long
long
l
o
n
g
long
long,可以通过
L
u
c
a
s
Lucas
Lucas定理取模解决。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int Max=20;
int n,m,ans;
int num[Max];
inline int ksm(int a,int b)
{
int ans=1;
a%=mod;
while(b)
{
if(b&1) ans=(ans*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ans;
}
inline int C(int n,int m)
{
if(n>=0&&m>=0&&n>=m)
{
int s1=1,s2=1;
for(int i=m-1;~i;i--)
{
s1=s1*(n-i)%mod;
s2=s2*(i+1)%mod;
}
return s1*ksm(s2,mod-2)%mod;
}
else return 0;
}
inline int Lucas(int n,int m)
{
if(!m) return 1;
return (C(n%mod,m%mod)*Lucas(n/mod,m/mod))%mod;
}
signed main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>num[i];
for(int k=0;k<(1<<n);k++)
{
int p=0,t=n+m;
for(int i=0;i<n;i++)
{
if(!((1<<i)&k)) continue;
t-=num[i],p++;
}
if(t-p-1<0) continue; //注意特判
t-=p+1;
if(p&1) ans=(ans-Lucas(t,n-1))%mod;
else ans=(ans+Lucas(t,n-1))%mod;
}
cout<<(ans%mod+mod)%mod;
return 0;
}