zoukankan      html  css  js  c++  java
  • 组合数学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;
    }
    
  • 相关阅读:
    [工作积累点滴整理]虚拟化、云计算配置规划<一>
    视频监控——从其他浏览器打开低版本IE方案
    好记性不如烂笔头-nginx安装环境与Linux安装ftp组件
    (阿里巴巴)数据库连接池——Druid (未完持续更新)
    条形码和二维码编码解码工具类源码
    JS防抖与节流函数封装
    根据设备width(375)动态设置font-size
    JS写一个简单日历
    js常用身份校验规则
    list之flex布局写法及禁止橡皮筋效果
  • 原文地址:https://www.cnblogs.com/karryW/p/11777775.html
Copyright © 2011-2022 走看看