[HDU3037]Saving Beans(组合数学Lucas定理)

本文介绍了一种使用组合数学中的插板法解决特定问题的方法。具体地,文章探讨了从不同树上取豆子的不同组合方式,并通过数学推导给出了求解公式。此外,还介绍了如何利用Lucas定理来快速计算模意义下的组合数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

传送门
从n棵不同的树上取不超过M颗豆子(豆子无差异),有多少种取法。

题解

考虑如何求解 x1+x2+...+xn=m 的解的个数
可以用插板法求解。由于原题 xi 可以为0,但是插板法不能为0,那么可以等式两边同时+n
x1+1+x2+1+...+xn+1=n+m
这样就相当于有n+m个物品,将其分成n组的方案数,即 Cn1n+m1=Cmn+m1
那么这道题就是要求 i=0mCin+i1=C0n1+C1n+C2n+1+...+Cmn+m1
先把第一项写成 C0n 然后利用 Cji=Cji1+Cj1i1 可以将前两项合并然后继续和后面合并
最后答案就是 Cmn+m
利用Lucas定理可以快速求解 Cmn%p ,阶乘预处理一下就行了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long

int T;
LL n,m,Mod,mul[100005];

void calc()
{
    mul[0]=1LL;
    for (LL i=1;i<=Mod;++i) mul[i]=mul[i-1]*i%Mod;
}
LL fast_pow(LL a,LL p)
{
    LL ans=1LL;
    for (;p;p>>=1,a=a*a%Mod)
        if (p&1)
            ans=ans*a%Mod;
    return ans;
}
LL inv(LL x)
{
    return fast_pow(x,Mod-2)%Mod;
}
LL C(LL n,LL m)
{
    if (m>n) return 0LL;
    return mul[n]*inv(mul[m]*mul[n-m]%Mod)%Mod;
}
LL lucas()
{
    LL ans=1LL;
    while (m)
    {
        ans=ans*C(n%Mod,m%Mod)%Mod;
        n/=Mod,m/=Mod;
    }
    return ans;
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%I64d%I64d%I64d",&n,&m,&Mod);
        calc();
        n+=m;
        printf("%I64d\n",lucas());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值