题解 十二重计数
题目描述
有 \(n\) 个球和 \(m\) 个盒子,要全部装进盒子里。
还有一些限制条件,那么有多少种方法放球?(与放的先后顺序无关)
限制条件如下:
\(\text{I}\):球之间互不相同,盒子之间互不相同。
\(\text{II}\):球之间互不相同,盒子之间互不相同,每个盒子至多装一个球。
\(\text{III}\):球之间互不相同,盒子之间互不相同,每个盒子至少装一个球。
\(\text{IV}\):球之间互不相同,盒子全部相同。
\(\text{V}\):球之间互不相同,盒子全部相同,每个盒子至多装一个球。
\(\text{VI}\):球之间互不相同,盒子全部相同,每个盒子至少装一个球。
\(\text{VII}\):球全部相同,盒子之间互不相同。
\(\text{VIII}\):球全部相同,盒子之间互不相同,每个盒子至多装一个球。
\(\text{IX}\):球全部相同,盒子之间互不相同,每个盒子至少装一个球。
\(\text{X}\):球全部相同,盒子全部相同。
\(\text{XI}\):球全部相同,盒子全部相同,每个盒子至多装一个球。
\(\text{XII}\):球全部相同,盒子全部相同,每个盒子至少装一个球。
由于答案可能很大,所以要对 \(998244353\) 取模。
输入格式
输入一行,两个数字,分别为\(n\)和\(m\)
输出格式
输出十二行,每行一个整数,对应每一种限制条件的答案。
样例输入:
13 6
样例输出:
83517427
0
721878522
19628064
0
9321312
8568
0
792
71
0
14
数据范围与提示
对于\(50\%\)数据,\(n,m\le 1000\)
对于\(100\%\)数据,\(n,m\le 10000\)
解题思路
组合数学入门题大合集对于\(12\)种情况讨论即可
\(\text{I}\):球之间互不相同,盒子之间互不相同。
显然的我们有总方案数为\(m^n\)
\(\text{II}\):球之间互不相同,盒子之间互不相同,每个盒子至多装一个球。
考虑每次放进一个盒子之后都减一,最后为\(m\times (m-1) \times (m-2).....\times (m-n+1)=m^{\underline{n}}\)
\(\text{III}\):球之间互不相同,盒子之间互不相同,每个盒子至少装一个球。
考虑第二类斯特林数,对于\(\begin{Bmatrix}n\\m\end{Bmatrix}\)的意义为将有\(n\)个物品的集合划分到\(m\)个非空集合,可以看做盒子相同的情况,乘上\(m!\)为盒子不同的情况
同时也可以考虑容斥:枚举多少个盒子空了,然后剩下的部分就是第一个部分了。然后就可以得到下面这个式子:
\(\text{IV}\):球之间互不相同,盒子全部相同。
用第二类斯特林数枚举装了多少个球,即为
\(\text{V}\):球之间互不相同,盒子全部相同,每个盒子至多装一个球。
无论球在哪个盒子都是一样的,即为
\(\text{VI}\):球之间互不相同,盒子全部相同,每个盒子至少装一个球。
显然直接第二类斯特林数
或者二项式反演
此为第二类斯特林数通项公式。
\(\text{VII}\):球全部相同,盒子之间互不相同。
隔板法即可,最后答案为
\(\text{VIII}\):球全部相同,盒子之间互不相同,每个盒子至多装一个球。
相当于选\(n\)个盒子装球,方案为
\(\text{IX}\):球全部相同,盒子之间互不相同,每个盒子至少装一个球。
同样利用插板法,我们先钦定每个盒子里头放一个球,剩下 \(n-m\) 个球按照第七个做就行了。
\(\text{X}\):球全部相同,盒子全部相同。
设 \(dp_{n,m}\) 将 \(n\)个球 分到 \(m\) 个相同的方案数。那么我们要的答案就是 \(dp_{n,m}\)
显然有一个\(n^2\)的\(dp\)转移柿子为
两者的意思分别为:对于有空盒子的情况去掉一个空盒子(等号右边),无空盒子则从每个盒子里减\(1\)个球。
可以对其构造生成函数,
然后不难发现
于是就有
直接暴力多项式\(exp\)即可做到\(O(nlogn)\)
\(\text{XI}\):球全部相同,盒子全部相同,每个盒子至多装一个球。
和第五个是一样的东西
\(\text{XII}\):球全部相同,盒子全部相同,每个盒子至少装一个球。
我们强制现在每个盒子里头放一个球,就是和\(\text{X}\)同样的问题了。答案即为 \(dp_{n-m,m}\)
#include<bits/stdc++.h>
#define LL long long
#define _ 0
#define R register
using namespace std;
/*Grievous Lady*/
template <typename _n_> void mian(_n_ & _x_){
_x_ = 0;int _m_ = 1;char buf_ = getchar();
while(buf_ < '0' || buf_ > '9'){if(buf_ == '-')_m_ =- 1;buf_ = getchar();}
do{_x_ = (_x_ << 1) + (_x_ << 3) + buf_ - '0';buf_ = getchar();}while(buf_ >= '0' && buf_ <= '9');_x_ *= _m_;
}
// #define int long long
#define mod 998244353
const int kato = 1e6 + 10;
int n , m , len;
int fac[kato] , inv[kato] , fac_inv[kato] , A[kato] , B[kato] , S[kato] , F[kato];
#define init() \
{ \
for(len = 1;len <= (max(n , m) << 1);len <<= 1); \
fac[0] = fac[1] = inv[0] = inv[1] = fac_inv[0] = fac_inv[1] = 1; \
for(R int i = 2;i <= n + m;i ++){ \
fac[i] = 1LL * fac[i - 1] * i % mod; \
inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod; \
fac_inv[i] = 1LL * fac_inv[i - 1] * inv[i] % mod; \
} \
for(R int i = 0;i <= n;i ++){ \
A[i] = (i & 1) ? mod - fac_inv[i] : fac_inv[i]; \
B[i] = fac_inv[i] * 1LL * quick_pow(i , n) % mod; \
} \
}
inline int quick_pow(int a , int b){
R int res = 1;
for(; b ; b >>= 1 , a = 1LL * a * a % mod){
if(b & 1){
res = 1LL * res * a % mod;
}
}
return res;
}
inline int c(int a , int b){
if(a < b) return 0;
return 1LL * fac[a] * fac_inv[b] % mod * fac_inv[a - b] % mod;
}
inline void NTT(int *y , int len , int opt){
R int *rev = new int[len];
rev[0] = 0;
for(R int i = 1;i < len;i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) * (len >> 1));
for(R int i = 0;i < len;i ++) if(i < rev[i]) swap(y[i] , y[rev[i]]);
for(R int i = 1;i < len;i <<= 1){
R int g1 = quick_pow(3 , (mod - 1) / (i << 1));
for(R int j = 0;j < len;j += (i << 1)){
for(R int k = 0 , g = 1;k < i;k ++ , g = g * 1LL * g1 % mod){
R int res = y[i + k + j] * 1LL * g % mod;
y[i + k + j] = ((y[j + k] - res) % mod + mod) % mod;
y[j + k] = (y[j + k] + res) % mod;
}
}
}
if(opt == -1){
reverse(y + 1 , y + len);
for(R int i = 0 , inv = quick_pow(len , mod - 2);i < len;i ++) y[i] = y[i] * 1LL * inv % mod;
}
delete []rev;
}
void poly_inv(int *a , int len){
if(len == 1){ a[0] = quick_pow(a[0] , mod - 2); return;}
R int len1 = len / 2;
R int *g = new int[len * 2];
for(R int i = 0;i < len1;i ++) g[i] = a[i];
for(R int i = len1;i < len * 2;i ++) g[i] = 0;
poly_inv(g , len1);
for(R int i = len1;i < len * 2;i ++) g[i] = 0;
NTT(g , len * 2 , 1) , NTT(a , len * 2 , 1);
for(R int i = 0;i < len * 2;i ++) a[i] = ((2 * g[i] % mod - a[i] * 1LL * g[i] % mod * g[i] % mod) % mod + mod) % mod;
NTT(a , len * 2 , -1);
for(R int i = len;i < len * 2;i ++) a[i] = 0;
delete []g;
}
inline void poly_dev(int *a , int len){
for(R int i = 1;i < len;i ++) a[i - 1] = a[i] * 1LL * i % mod;
a[len - 1] = 0;
}
inline void poly_dev_inv(int *a , int len){
for(R int i = len + 1 ; i ; i --) a[i] = a[i - 1] * 1LL * inv[i] % mod;
a[0] = 0;
}
inline void get_ln(int *a, int len){
R int *b = new int[len * 2];
for(R int i = 0;i < len;i ++) b[i] = a[i];
for(R int i = len;i < len << 1;i ++) b[i] = 0;
poly_dev(b , len); poly_inv(a , len);
NTT(a , len << 1 , 1); NTT(b , len << 1 , 1);
for(R int i = 0;i < len << 1;i ++) a[i] = a[i] * 1LL * b[i] % mod;
NTT(a , len << 1 , -1);
poly_dev_inv(a , len);
for(R int i = len;i < len << 1;i ++) a[i] = 0;
delete []b;
}
void poly_exp(int *a , int len){
if(len == 1) { a[0] ++; return; }
int len1 = len / 2;
int *g = new int[len << 1];
for(int i = 0;i < len1;i ++) g[i] = a[i];
for(int i = len1;i < len << 1;i ++) g[i] = 0;
poly_exp(g , len1);
for(int i = len1;i < len << 1;i ++) g[i] = 0;
int *lng = new int[len << 1];
for(int i = 0;i < len << 1;i ++) lng[i] = g[i];
get_ln(lng , len); a[0] ++;
for(int i = 0;i < len;i ++){ a[i] -= lng[i]; if (a[i] < 0) a[i] += mod; }
NTT(a , len << 1 , 1); NTT(g , len << 1 , 1);
for(int i = 0;i < len << 1;i ++) a[i] = a[i] * 1LL * g[i] % mod;
NTT(a , len << 1 , -1);
for(int i = len;i < len << 1;i ++) a[i] = 0;
delete []g;
}
inline int solve_I(){
return quick_pow(m , n);
}
inline int solve_II(){
R int res = 1;
for(R int i = m ; i >= m - n + 1 ; i --){
res = 1LL * res * i % mod;
}
return res;
}
inline int solve_III(){
return 1LL * S[m] * fac[m] % mod;
}
inline int solve_IV(){
int res = 0;
for(R int i = 1;i <= m;i ++){
res = (res + S[i]) % mod;
}
return res % mod;
}
inline int solve_V(){
return n > m ? 0 : 1;
}
inline int solve_VI(){
return n < m ? 0 : S[m];
}
inline int solve_VII(){
return c(n + m - 1 , m - 1);
}
inline int solve_VIII(){
return c(m , n);
}
inline int solve_IX(){
return c(n - 1 , m - 1);
}
inline int solve_X(){
return F[n];
}
inline int solve_XI(){
return n > m ? 0 : 1;
}
inline int solve_XII(){
return n < m ? 0 : F[n - m];
}
inline int Ame_(){
mian(n) , mian(m); init();
NTT(A , len , 1); NTT(B , len , 1);
for(R int i = 0;i < len;i ++) A[i] = 1LL * A[i] * B[i] % mod;
NTT(A , len , -1);
for(R int i = 0;i <= n;i ++) S[i] = A[i];
for(R int i = 1;i <= m;i ++){
for(R int j = i;j <= n;j += i){
F[j] = (F[j] + inv[j / i]) % mod;
}
}
poly_exp(F , len / 2);
printf("%d\n" , solve_I());
printf("%d\n" , solve_II());
printf("%d\n" , solve_III());
printf("%d\n" , solve_IV());
printf("%d\n" , solve_V());
printf("%d\n" , solve_VI());
printf("%d\n" , solve_VII());
printf("%d\n" , solve_VIII());
printf("%d\n" , solve_IX());
printf("%d\n" , solve_X());
printf("%d\n" , solve_XI());
printf("%d\n" , solve_XII());
fclose(stdin); fclose(stdout);
return ~~(0^_^0);
}
int Ame__ = Ame_();
signed main(){;}