组合数学12

将有标号记为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;
}
原文地址:https://www.cnblogs.com/karryW/p/11777775.html