将有标号记为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; }