将有标号记为L(labelled) 无标号记为U(unlabelled)
A.无限制
B.每个盒子至少有一个球
C.每个盒子至多有一个球
LLA
每个小球都有\(m\)种放法,所以就是\(m^n\)。
LLB
第二类斯特林数是要求盒子都一样,所以我们先算出来盒子都一样的方案数,再乘上一个\(m!\)就行了。
第二类斯特林数:
\(f[i][j]\)表示\(i\)个小球放进\(j\)个盒子里,每个盒子至少有一个小球的方案数。
转移方程:
\(f[i][j]=f[i-1][j]*j+f[i-1][j-1]\)。
理解:
考虑最后一个小球,一种情况是它单独一个盒子,这样方案数就是\(f[i-1][j-1]\)(前j-1个球放进i-1个盒子里的方案数)。另一种情况是它和其他小球放进一个盒子里,这样先把前i-1个小球放好,也就是\(f[i-1][j]\),然后第i个小球有j种选择,所以这种情况的方案数为\(j*f[i-1][j]\)。
LLC
C 的情况当盒子数小于小球数是答案为0,以下默认盒子数大于小球数
每个盒子至多放一个,也就是说每个盒子只有两种情况:放和不放。
有\(n\)个小球,也就是说有\(n\)个盒子放,\(m-n\)个盒子不放。\(C_m^n\)从m个盒子中选出\(n\)个来放小球。然后n个有标号的小球放进这n个盒子里有\(n!\)种放法。
LUA
第二类斯特林数再稍微加点东西。
枚举有几个盒子为空,所有的方案数加起来。
LUB
标准的第二类斯特林数。
LUC
如果能放的话,不管怎么放都是一样的。每个球占一个盒子,盒子都一样。
ULA
隔板法解决不了有空盒子的情况。所以我们把小球变成\(n+m\)个,相当于预先把每个盒子里放一个小球,最后再拿走。
方案数:\(C_{n+m-1}^{m-1}\)
ULB
直接上隔板法 \(C_{n-1}^{m-1}\)
ULC
从\(m\)个盒子中选出\(n\)个放小球。
\(C_m^n\)
UUA
DP
\(f[i][j]\)表示\(i\)个小球放进\(j\)个盒子里的方案数。
转移:
一种情况是有空盒,由\(f[i][j-1]\)转移过来,也就是有一个空盒的情况。只由这一种转移过来,两个及以上的空盒会包含在这里边。因为\(f[i][j-1]\)的答案已经算好了,这里面一定有有空盒的情况。
一种情况是没有空盒,先拿出\(j\)个小球来,每个盒子里放一个,也就是由\(f[i-j][j]\)转移过来。
UUB
先拿出\(m\)个小球每个盒子里放进一个,然后就和UUA一样了。
UUC
除了不合法的情况,就只有一种放法。
(不是我的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
inline void read(ll &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(ll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
}
const int N=100010;
const int mod=998244353;
string s;
ll n,m,f[1005][1005];
ll pow(ll x,ll y)
{
ll ret=1;
while(y)
{
if(y&1)
ret=ret*x%mod;
x=x*x%mod;
y=y>>1;
}
return ret;
}
ll C(ll x,ll y)
{
if(y>x) return 0;
ll a=1,b=1;
for(ll i=x-y+1;i<=x;i++)
a=a*i%mod;
for(ll i=2;i<=y;i++)
b=b*i%mod;
return a*pow(b,mod-2)%mod;
}
ll lucas(ll x,ll y)
{
if(!y)
return 1;
else
return (C(x%mod,y%mod)*lucas(x/mod,y/mod))%mod;
}
ll calt(ll x,ll y)
{
if(x==0 || y==1)
{
f[x][y]=1;
return f[x][y];
}
if(y>x)
{
if(f[x][x])
return f[x][x];
else
{
f[x][x]=calt(x,x);
return f[x][x];
}
}
ll ans1,ans2;
if(f[x][y-1])
ans1=f[x][y-1];
else
{
f[x][y-1]=calt(x,y-1);
ans1=f[x][y-1];
}
if(f[x-y][y])
{
ans2=f[x-y][y];
}
else
{
f[x-y][y]=calt(x-y,y);
ans2=f[x-y][y];
}
return (ans1+ans2)%mod;
}
ll cal(ll x,ll y)
{
for(int i=0;i<=y;i++) f[0][i]=1;
for(int i=0;i<=x;i++) f[i][1]=1;
for(ll i=1;i<=x;i++)
for(ll j=1;j<=y;j++)
{
if(j>i) f[i][j]=f[i][i];
else f[i][j]=(f[i-j][j]+f[i][j-1])%mod;
}
return f[x][y];
}
int main()
{
cin>>s;
read(n),read(m);
if(s=="UUA")
{
print(cal(n,m));
}
if(s=="UUB")
{
if(n>=m)
{
print(cal(n-m,m));
}
else
{
print(0);
}
}
if(s=="UUC")
{
if(n<=m)
print(1);
else
print(0);
}
if(s=="ULA")
{
print(lucas(n+m-1,m-1));
}
if(s=="ULB")
{
print(lucas(n-1,m-1));
}
if(s=="ULC")
{
if(n<=m)
print(lucas(m,n));
else
print(0);
}
if(s=="LUA")
{
for(int i=0;i<=n;i++)
f[i][i]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
f[i][j]=(j*f[i-1][j]%mod+f[i-1][j-1])%mod;
ll ans=0;
for(int i=1;i<=m;i++)
ans=(ans+f[n][i])%mod;
print(ans);
}
if(s=="LUB")
{
if(n>=m)
{
for(int i=0;i<=n;i++)
f[i][i]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
f[i][j]=(j*f[i-1][j]%mod+f[i-1][j-1])%mod;
print(f[n][m]);
}
else
{
print(0);
}
}
if(s=="LUC")
{
if(n<=m)
print(1);
else
print(0);
}
if(s=="LLA")
{
print(pow(m,n));
}
if(s=="LLB")
{
ll sum=1;
for(int i=1;i<=m;i++)
sum=(sum*i)%mod;
for(int i=0;i<=n;i++)
f[i][i]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
f[i][j]=(j*f[i-1][j]%mod+f[i-1][j-1])%mod;
print(sum*f[n][m]%mod);
}
if(s=="LLC")
{
if(n<=m)
{
ll sum=1;
for(int i=1;i<=n;i++)
sum=(sum*i)%mod;
print(sum*lucas(m,n)%mod);
}
else
{
print(0);
}
}
return 0;
}