组合数例题

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
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<

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
#include
#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=i)
        ans=(ans+(ksc(ksc(ksc(C(m,i),f[n][i]),ksm(m-i,n)),jie(i)))%mod)%mod;
        
    }
    cout<

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)\)

你可能感兴趣的:(组合数例题)