假如有(n)个球,要放进(m)个盒子,求方案数。
( ext{I}):球之间互不相同,盒子之间互不相同。
显然答案为(m^n)。
( ext{II}):球之间互不相同,盒子之间互不相同,每个盒子至多装一个球。
依次把球放进盒子,放第(i)个球时有(m-i+1)种方案,因此答案为(m^{underline n})。
( ext{III}):球之间互不相同,盒子之间互不相同,每个盒子至少装一个球。
相当于把(n)个数划分为(m)个有序集合,因此答案为(left{natop m ight}m!)。
( ext{IV}):球之间互不相同,盒子全部相同。
枚举有多少个盒子放了球,然后方案数就是将(n)个数划分为若干个无序集合,因此答案为(sumlimits_{i=1}^mleft{natop i ight})。
( ext{V}):球之间互不相同,盒子全部相同,每个盒子至多装一个球。
显然答案为([nle m])。
( ext{VI}):球之间互不相同,盒子全部相同,每个盒子至少装一个球。
显然答案为(left{natop m ight})。
( ext{VII}):球全部相同,盒子之间互不相同。
每个盒子装任意个球都只有一种方案,OGF为(frac1{1-x}),因此答案为([x^n]frac1{(1-x)^m}={n+m-1choose n})。
( ext{VIII}):球全部相同,盒子之间互不相同,每个盒子至多装一个球。
显然答案为({mchoose n})。
( ext{IX}):球全部相同,盒子之间互不相同,每个盒子至少装一个球。
此时每个盒子装球的OGF为(frac x{1-x}),因此答案为([x^n]frac{x^m}{(1-x)^m}={n-1choose m-1})。
( ext{X}):球全部相同,盒子全部相同。
相当于将(n)划分为(m)个无序自然数的和,答案为(p(n+m,m)=[x^n]prodlimits_{i=1}^mfrac1{1-x^i})。
( ext{XI}):球全部相同,盒子全部相同,每个盒子至多装一个球。
显然答案为([nle m])。
( ext{XII}):球全部相同,盒子全部相同,每个盒子至少装一个球。
相当于将(n)划分为(m)个无序正整数的和,答案为(p(n,m)=[x^{n-m}]prodlimits_{i=1}^mfrac1{1-x^i})。
#include<cstdio>
#include<cstring>
#include<numeric>
#include<algorithm>
const int N=524289,P=998244353;
int n,m,deg,len,fac[N],inv[N],ifac[N],rev[N],w[N],S[N],p[N];
int inc(int a,int b){return a+=b-P,a+=a>>31&P;}
int dec(int a,int b){return a-=b,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int C(int n,int m){return m<0||m>n? 0:mul(mul(fac[n],ifac[m]),ifac[n-m]);}
int getlen(int n){return 1<<(32-__builtin_clz(n));}
void init(int n)
{
int lim=1<<(len=32-__builtin_clz(n)),g=pow(3,(P-1)/lim);
w[lim>>1]=1,fac[0]=ifac[0]=inv[0]=fac[1]=ifac[1]=inv[1]=1;
for(int i=1;i<lim;++i) rev[i]=(rev[i>>1]>>1)|(i&1? lim>>1:0);
for(int i=(lim>>1)+1;i<lim;++i) w[i]=mul(w[i-1],g);
for(int i=(lim>>1)-1;i;--i) w[i]=w[i<<1];
for(int i=2;i<=lim;++i) fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[i-1],inv[i]=mul(inv[P%i],P-P/i));
}
void NTT(int*a,int lim,int f)
{
if(!~f) std::reverse(a+1,a+lim);
for(int i=0,x=len-__builtin_ctz(lim);i<lim;++i) if(i<rev[i]>>x) std::swap(a[i],a[rev[i]>>x]);
for(int i=1;i<lim;i<<=1) for(int j=0,d=i<<1;j<lim;j+=d) for(int k=0,x;k<i;++k) x=mul(a[i+j+k],w[i+k]),a[i+j+k]=dec(a[j+k],x),a[j+k]=inc(a[j+k],x);
if(!~f) for(int i=0,x=P-(P-1)/lim;i<lim;++i) a[i]=mul(a[i],x);
}
void Inv(int*a,int*b,int deg)
{
if(deg==1) return b[0]=pow(a[0],P-2),void();
static int t[N];int lim=getlen(deg*2-2);
Inv(a,b,(deg+1)>>1),memcpy(t,a,deg<<2),memset(t+deg,0,(lim-deg)<<2);
NTT(t,lim,1),NTT(b,lim,1);
for(int i=0;i<lim;++i) b[i]=mul(dec(2,mul(b[i],t[i])),b[i]);
NTT(b,lim,-1),memset(b+deg,0,(lim-deg)<<2);
}
void Der(int*a,int*b,int deg){for(int i=1;i<deg;++i)b[i-1]=mul(a[i],i);b[deg-1]=0;}
void Int(int*a,int*b,int deg){for(int i=1;i<deg;++i)b[i]=mul(a[i-1],inv[i]);b[0]=0;}
void Ln(int*a,int*b,int deg)
{
static int t[N];int lim=getlen(deg*2-2);
Inv(a,t,deg),Der(a,b,deg),NTT(t,lim,1),NTT(b,lim,1);
for(int i=0;i<lim;++i) t[i]=mul(t[i],b[i]);
NTT(t,lim,-1),Int(t,b,deg),memset(t,0,lim<<2),memset(b+deg,0,(lim-deg)<<2);
}
void Exp(int*a,int*b,int deg)
{
if(deg==1) return b[0]=1,void();
static int t[N];int lim=getlen(deg*2-2);
Exp(a,b,(deg+1)>>1),Ln(b,t,deg);
for(int i=0;i<deg;++i) t[i]=dec(a[i],t[i]);
memset(t+deg,0,(lim-deg)<<2),++t[0],NTT(t,lim,1),NTT(b,lim,1);
for(int i=0;i<lim;++i) b[i]=mul(b[i],t[i]);
NTT(b,lim,-1),memset(b+deg,0,(lim-deg)<<2),memset(t+deg,0,(lim-deg)<<2);
}
void calcS()
{
static int F[N],G[N],lim=1<<len,deg=std::min(n,m)+1;
for(int i=0;i<deg;++i) F[i]=mul(pow(i,n),ifac[i]),G[i]=i&1? P-ifac[i]:ifac[i];
NTT(F,lim,1),NTT(G,lim,1);
for(int i=0;i<lim;++i) S[i]=mul(F[i],G[i]);
NTT(S,lim,-1),memset(S+deg,0,(lim-deg)*4);
}
void calcp()
{
static int F[N];
for(int i=1;i<=m;++i) for(int j=i;j<=n;j+=i) F[j]=inc(F[j],inv[j/i]);
Exp(F,p,n+1);
}
int main()
{
scanf("%d%d
",&n,&m);
init(2*std::max(n,m)),calcS(),calcp();
printf("%d
",pow(m,n));
printf("%d
",mul(C(m,n),fac[n]));
printf("%d
",mul(S[m],fac[m]));
printf("%d
",std::accumulate(S+1,S+m+1,0,inc));
printf("%d
",n<=m);
printf("%d
",S[m]);
printf("%d
",C(m+n-1,n));
printf("%d
",C(m,n));
printf("%d
",C(n-1,m-1));
printf("%d
",p[n]);
printf("%d
",n<=m);
printf("%d
",n<m? 0:p[n-m]);
}