组合数学12

此生再无相见时 提交于 2019-12-03 04:38:01

将有标号记为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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!