组合数例题

Posted oieredsion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组合数例题相关的知识,希望对你有一定的参考价值。

1.糖果盒 nkoj 4052

问题:
何老板有很多颗相同的糖果,同时还有n个不同的糖果盒。何老板想把其中一些糖果放入这些盒子里,要求所有盒子里总的糖果数不超过m,问总共有多少种不同的方案?
每个盒子的容量无限大,可以选择装糖,也可以不装。
答案可能很大,mod p后在输出,p是一个素数。

解:
假设有k个糖果要装进n个糖果盒里面
增设空格子 利用插板原理 答案为\(c(n+m-1,m-1)\)

所以不超过m的答案为\(\sum _i=1^i=m c(n+i-1,i-1)\)
注意到\(c(n ,0) =1\) 所以可以换成\(c(n+1,0)\)就递推就行了,
我们有组合数公式 \(C(N,M)=C(N-1,M)+C(N-1,M-1)\)
于是就可以递推
最终答案为\(C(n+m,m)\)
code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
ll n,m,p;
ll ksm(ll a,ll b)

    ll ans=1;
    while(b)
    
        if(b&1) ans=(ans*a)%p;
        a=(a*a)%p;
        b>>=1;
    
    return ans%p;

ll C(ll x,ll y)

    ll A=1,B=1;
    for(int i=1;i<=y;i++)
    
        A=(A*(x-y+i)%p)%p;
        B=(B*(i)%p)%p;
    
    return (A*ksm(B,p-2))%p;
    

ll lucas(ll x,ll y)

    if(y==0) return 1;
    return (C(x%p,y%p)*lucas(x/p,y/p))%p;

int main()

    cin>>n>>m>>p;
    cout<<lucas(n+m,m)%p;

2.nkoj 4502 装糖果

NK小卖部有m种不同口味的糖果出售。
何老板委托你去买2*n颗糖装入两个盒子里,每个盒子里有一排n个方格,每个方格只能装1颗糖。何老板要求,两个盒子里不能有相同口味的糖果(同一个盒子里可以有口味相同的)。
那么问题来了,总共有多少种方案呢?
1≤n,m≤2000

此题有两种做法

1.
首先 两个盒子就是两个变量
我们想到先确定一个变量
那么我们就枚举 第一个箱子确定装的\(i\)种糖果 那么第二个箱子就装的
\(m-i\)种糖果 那么第二种箱子的方案数为 \((m-i)^n\)
讨论第一种箱子
你就会想到是 将n个盒子划分成i个非空集合 这不就是第二类斯特林数吗???
但是他有排列顺序 没关系 我们 times \(A_i^i\) 就行了(这里没有搞懂 准备明天再去问)
答案就是\(\sum _i=1^i=m-1 (C(m,i)\times f[n][i]\times(A_i^i)\times (m-i)^n)\)

code:

#include<iostream>
#include<cstdio>
#define mod 1000000007
using namespace std;
#define maxnn 2005
#define ll long long
using namespace std;
ll f[maxnn][maxnn];
ll n,m;
ll ksm(ll a,ll b)

    ll ans=1;
    while(b)
    
        if(b&1) ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    
    return ans%mod;

ll C(ll n,ll m)

    ll A=1,B=1;
    for(int i=1;i<=m;i++)
    
        A=A*(n-m+i)%mod;
        B=B*(i)%mod;
    
    return A*ksm(B,mod-2)%mod;

ll ksc(ll a,ll b)

    ll ans=0;
    while(b)
    
        if(b&1) ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    
    return ans%mod;

ll jie(ll n)

    ll ans=1;
    for(int i=1;i<=n;i++)
    
        ans=(ans*i)%mod;
    
    return ans%mod;

int main()

    cin>>n>>m;
    f[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
        
            f[i][j]=(f[i-1][j-1]+f[i-1][j]*j)%mod;
        
    ll ans=0;
    for(int i=1;i<m;i++)
    
        if(n>=i)
        ans=(ans+(ksc(ksc(ksc(C(m,i),f[n][i]),ksm(m-i,n)),jie(i)))%mod)%mod;
        
    
    cout<<ans%mod;

2.
假设f[i][j] 为前i个箱子装j种不同的糖果的方案

\(f[i][j]=f[i-1][j-1]*(m-j+1)+f[i-1][j]*j;\)
然后这里已经枚举了排列
所以答案为
\(\sum _i=1^i=m-1 (f[n][i]\times (m-i)^n)\)

以上是关于组合数例题的主要内容,如果未能解决你的问题,请参考以下文章

小航的算法日记组合数

卡特兰数 性质例题及源码实现

一道有关排列组合的问题(求正整数s分成n个正整数的方法数)

java例题_11 求不重复数

「总结」多项式生成函数例题

c++两个数组合并成一个新数组