十二重计数法 题解
\(146\) 行,有 \(80\) 行都是多项式板子(主要 \(\exp\) 真的长)。可以说涵盖了相当一部分球盒模型了,当然算是比较基础的小练习。
好了开始。
题意
\(n\) 个球放到 \(m\) 个盒子里,在以下的十二种限制条件(球相同/不同,盒子相同/不同,每个盒子无限制/至多一个球/至少一个球)下求方案数。
题解
\(\text{I}\) :球互不相同,盒子互不相同。
每个球都有 \(m\) 种不同的放法, \(n\) 个球,总数就是 \(m^n\) 。
\(\text{II}\) :球互不相同,盒子互不相同,每个盒子至多一个球。
相当于从 \(m\) 个盒子里选出 \(n\) 个来放球,显然是 \(A_m^n\) 。
\(\text{III}\) :球互不相同,盒子互不相同,每个盒子至少一个球。
注意我们不能先每个盒子钦定放进去一个球然后剩下的随便放。因为这样会算重复。
举个例子:考虑 \(n=5,m=4\) 的情况:一开始我们随便放四个球(比如 \(1,2,3,4\) ),然后放第 \(5\) 个(假如和 \(1\) 放一块),那么这个方案就是 \(\{1,5\},\{2\},\{3\},\{4\}\) 。然后再选四个( \(2,3,4,5\) ),然后放第 \(1\) 个,如果按照上面的算,那么就可以和第 \(5\) 个放一块,就算重复了。
我们发现这个就是把 \(1-n\) 这 \(n\) 个元素分成 \(m\) 个有序集合,而分成 \(m\) 个无序集合的方案数显然是 \(\begin{Bmatrix}n \\ m\end{Bmatrix}\) 。然后我们要变得有序,直接乘一个 \(m!\) 就行了。答案就是 \(m!\begin{Bmatrix}n \\ m\end{Bmatrix}\) 。
\(\text{IV}\) :球互不相同,盒子全部相同。
一开始想到了贝尔数,但是贝尔数是任意个集合。类推 \(Bell(n)=\sum_{i=0}^n\begin{Bmatrix}n \\ i\end{Bmatrix}\) ,我们可以想到枚举分了多少个盒子,于是答案就是
\(\text{V}\) :球互不相同,盒子全部相同,每个盒子至多一个球。
降智题。发现球比盒子多的时候没法放下,而球比盒子少的时候因为盒子相同所以怎么放都一样。所以答案就是 \([n\le m]\) 。
\(\text{VI}\) :球互不相同,盒子全部相同,每个盒子至少一个球。
这个比较水。规定每个盒子都有球,相当于把 \(1-n\) 这 \(n\) 个元素分成 \(m\) 个无序集合,显然是 \(\begin{Bmatrix}n\\m\end{Bmatrix}\) 。
\(\text{VII}\) :球全部相同,盒子互不相同。
别考虑什么别的东西(我考虑各种高深东西干不出来最后发现就是个插板)。既然球全部相同那么考虑如何把空的盒子去掉。我们添上 \(m\) 个球,然后把它们分成 \(m\) 组,于是就是 \(n+m-1\) 个空位中插入 \(m-1\) 个板,答案就是 \(\binom{n+m-1}{m-1}\) 。
\(\text{VIII}\) :球全部相同,盒子互不相同,每个盒子至多一个球。
现在球相同盒子不同,于是就变成了从 \(m\) 个盒子里选出 \(n\) 个放球,是 \(\binom{m}{n}\) 。
\(\text{IX}\) :球全部相同,盒子互不相同,每个盒子至少一个球。
既然每个盒子都有球了那就不需要新增球规定不为空了。直接插板,是 \(\binom{n-1}{m-1}\) 。
\(\text{XI}\) :球全部相同,盒子全部相同,每个盒子至多一个球。
同样是弱智题,也是 \([n\le m]\) 。
接下来是最难的两个(所以把 \(\text{XI}\) 放到前面了)。
\(\text{X}\) :球全部相同,盒子全部相同。
首先问题等价于求把 \(n\) 分拆成不超过 \(m\) 个无序整数的分拆数。由 \(\text{Ferrers}\) 图的结论可以知道,这个数就是只用 \(\le m\) 的数来分拆的方案数。
考虑分拆数的\(\text{OGF}\) (由于只用 \(\le m\) 的数分拆所以加上了上界):
按照套路取个 \(\ln\) 然后 \(\exp\) 回来:
直接暴力计算即可,答案即为第 \(n\) 项的值。
\(\text{XII}\) :球全部相同,盒子全部相同,每个盒子至少一个球。
由于球相同所以可以钦定每个盒子放一个球然后求解,答案就是上面那个多项式第 \(n-m\) 项的值。
代码一半是板子。板子没什么意思就不放了。
int A(int n,int m){
if(n<m)return 0;
return 1ll*jc[n]*inv[n-m]%mod;
}
int C(int n,int m){
if(n<m)return 0;
return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
}
int getstiring(int n,int m){
int ans=0;
for(int i=1;i<=m;i++){
ans=(ans+1ll*((m-i)&1?(mod-1):1)*C(m,i)%mod*qpow(i,n)%mod)%mod;
}
return 1ll*inv[m]*ans%mod;
}
void getstiring2(int n,int b[]){
for(int i=0;i<=n;i++){
a[i]=(i&1)?mod-inv[i]:inv[i];
b[i]=1ll*qpow(i,n)*inv[i]%mod;
}
n++;get(n<<1);
ntt(a,wl,1);ntt(b,wl,1);
for(int i=0;i<wl;i++)b[i]=1ll*a[i]*b[i]%mod;
ntt(b,wl,-1);
for(int i=n;i<wl;i++)b[i]=0;
}
void solve(){
printf("%d\n",qpow(m,n));//I
printf("%d\n",A(m,n));//II
printf("%lld\n",1ll*jc[m]*getstiring(n,m)%mod);//III
getstiring2(n,stiring);
int ans=0;
for(int i=0;i<=m;i++)ans=(ans+stiring[i])%mod;
printf("%d\n",ans);//IV
printf("%d\n",(n<=m));//V
printf("%d\n",getstiring(n,m));//VI
printf("%d\n",C(n+m-1,m-1));//VII
printf("%d\n",C(m,n));//VIII
printf("%d\n",C(n-1,m-1));//IX
for(int i=0;i<=n;i++)a[i]=0;
for(int i=1;i<=m;i++){
for(int j=i;j<=n;j+=i){
a[j]=(a[j]+qpow(j/i,mod-2))%mod;
}
}
getexp(n+1,a,b);
printf("%d\n",b[n]);//X
printf("%d\n",(n<=m));//XI
printf("%d\n",n>=m?b[n-m]:0);//XII
}
int main(){
scanf("%d%d",&n,&m);jc[0]=inv[0]=1;
for(int i=1;i<=n+m;i++)jc[i]=1ll*jc[i-1]*i%mod;
inv[n+m]=qpow(jc[n+m],mod-2);
for(int i=n+m-1;i>0;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
solve();
return 0;
}