排列组合---隔板法

 1、定义

  隔板法就是在n个元素间插入(b-1)个板,即把n个元素分成b组的方法。C(n-1,b-1)

 2、条件

  隔板法必须满足三个条件:

 (1)这n个元素必须相同,(2)所分成的每一组至少分得一个元素,(3)分成的组别彼此差异。

 3、示例  

(1)例如:某校组建一球队需16人,该校共10个班级,且每个班至少分配一个名额,共有几种情况。C(16-1,10-1)。

   对n件相同物品(或名额)分给m个人(或位置),允许若干个人(或位置)为空的问题,可以看成将这n件物品分成m组,允许若干组为空的问题.将n件物品分成m组,需要m-1块隔板,将这n件物品和m-1块隔板排成一排,占n+m-1位置,从这n+m-1个位置中选m-1个位置放隔板,因隔板无差别,故隔板之间无序,是组合问题,故隔板有Cn+m-1 m-1种不同的方法,再将物品放入其余位置,因物品相同无差别,故物品之间无顺序,是组合问题,只有1种放法,根据分步计数原理,共有Cn+m-1 m-1×1=Cn+m-1 m-1种排法

(2)求方程x1+x2+…+xk=n的非负整数解或正整数解

   解:正整数解:转化为10个相同的小球装入4个不同的盒子,每盒至少有一个,有C(10-1,4-1)=84种。

       非负整数解:转化为10个相同的小球装入4个不同的盒子,可以有空盒,有C(10+4-1,4-1)种。

(3)X个相同的球放入Y个不相同的盒子中,要求每个盒子至多N个球至少0个球,共有多少种不同的放法?

    首先对于m个球放入Y个盒中,每个盒中至少一个球的放法用隔板法可以得到,即相当于在m-1个位置中放入Y-1个挡板将m个球分为Y份,这样每份至少为1,为 C_{m-1}^{Y-1} ,

    而X个球放入Y个盒中,每个盒中至少0个球的放法相当于X+Y个球放入Y个盒中,每个盒中至少一个球的放法,即相当于将X+Y个球分入Y个盒中,再从每个盒中取出1球,为 C_{X+Y-1}^{Y-1}

    而对于指定t个盒子(例如1,2,3,···,t号盒子)中的球数至少为N+1个球的放法等同于将(X-t*(N+1))个球放入Y个盒中,每个盒中至少0个球的放法,即(X-t*(N+1))个球放入Y个盒中后,再在指定的t个盒中各放入N+1个球,为 C_{X-t*(N+1)+Y-1}^{Y-1}

    根据容斥原理,每个盒子至多N球的放法为 总放法-所有指定一个盒子的球数大于N的方法+所有指定两个盒子的球数大于N的方法-所有指定三个盒子的球数大于N的方法+······

即为 C_{X+Y-1}^{Y-1}-C_{Y}^{1}*C_{X-(N+1)+Y-1}^{Y-1}+C_{Y}^{2}*C_{X-2*(N+1)+Y-1}^{Y-1}+···+(-1)^{t}*C_{Y}^{t}*C_{X-t*(N+1)+Y-1}^{Y-1}+···

其中 t\in[1,\frac{X}{N+1}]

题目链接

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;

ll n,m,k;

const ll M=2*1e5+5;
ll fact[M],ifact[M];//fact[i]是i的阶乘,ifact[i]是阶乘的除法逆元,两者用于求组合数

ll pow_mod(ll n,ll k,ll mod) //快速幂求n^k余m的结果
{
    ll res=1;
    n=n%mod;
    while(k>0)
    {
        if(k&1)
            res=res*n%mod;
        n=n*n%mod;
        k>>=1;
    }
    return res;
}
void init()//初始化
{
    fact[0]=ifact[0]=1;
    for(int i=1;i<M;++i)
    {
        fact[i]=(fact[i-1]*i)%mod;
        ifact[i]=pow_mod(fact[i],mod-2,mod);
    }
}

ll C(ll n,ll m)//求组合数
{
    if(n<m)
        return 0;
    return  fact[n]*ifact[m]%mod*ifact[n-m]%mod;
}

int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64d%I64d%I64d",&n,&m,&k);
        ll X=k,Y=m,N=n-1;
        ll ans=C(X+Y-1,Y-1);
        for(ll t=1;t<=X/(N+1);t++)
        {
            if((t&1)==0)
            {
                ans=(ans+C(Y,t)*C(X+Y-1-t*(N+1),Y-1)%mod)%mod;
            }
            else
            {
                ans=(ans-C(Y,t)*C(X+Y-1-t*(N+1),Y-1)%mod+mod)%mod;
            }
        }
        printf("%I64d\n",ans%mod);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jinghui_7/article/details/81735692