您的位置:首页 > 其它

hdu 3037 Saving Beans(lucas定理模板)

2015-09-16 15:19 501 查看

题意:

求在n棵树上摘不超过m颗豆子的方案,结果对p取模。

解析:

题目可以转换成 x1+x2+……+xn=mx_1+x_2+……+x_n=m 有多少组解,m在题中可以取0~m。


利用插板法可以得出 x1+x2+……+xn=mx_1+x_2+……+x_n=m

解的个数为Cn−1n+m−1=Cmn+m−1C_{n+m-1}^{n-1}=C_{n+m-1}^m;


则题目解的个数可以转换成求 sum=C0n+m−1+C1n+m−1+C2n+m−1……+Cmn+m−1sum = C_{n+m-1}^0+C_{n+m-1}^1 + C_{n+m-1}^2……+C_{n+m-1}^m


利用公式Crn=Crn−1+Cr−1n−1==>sum=Cmn+mC_n^r = C_{n-1}^r+C_{n-1}^{r-1} == > sum=C_{n+m}^m。


那么答案,就是要求Cmn+m%pC_{n+m}^m\%p。


因为n,m很大,这里可以直接套用Lucas定理的模板即可。

关于Lucas定理

Lucas(n,m,p)=C(n%p,m%p,p)∗Lucas(n/p,m/p,p)Lucas(n,m,p) = C(n\%p,m\%p,p) * Lucas(n/p, m/p, p)

//这里可以采用对n分段递归求解

Lucas(x,0,p)=1Lucas(x, 0, p)=1

将n,mn,m分解变小之后问题又转换成了求(a/b)%p(a/b)\%p。

(a/b)%p(a/b)\%p可以转换成a∗Inv(b,p)a*Inv(b,p)

Inv(b,p)Inv(b, p)为b对p的逆元。

mymy codecode

[code]#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;  
typedef long long ll;
const int N = 100005;
ll fac
;

ll modpow(ll a, ll b, ll MOD) {
    ll ret = 1;
    while(b) {  
        if(b&1) ret = (ret*a)%MOD;
        a = (a*a)%MOD;
        b>>=1;
    }
    return ret;
}

ll getFactor(ll p) {
    fac[0] = 1;
    for(int i = 1; i <= p; i++)
        fac[i] = (fac[i-1]*i) % p;
}

ll Lucas(ll n, ll m, ll p) {  
    ll ret=1;
    while(n && m) {
        ll a = n%p, b = m%p;  
        if(a<b) return 0; 
        ret = (ret * fac[a] * modpow(fac[b]*fac[a-b]%p, p-2, p)) % p;
        n/=p;
        m/=p;
    }
    return ret;  
}  

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        ll n, m, p;
        scanf("%I64d%I64d%I64d", &n, &m, &p);
        getFactor(p);
        printf("%I64d\n",Lucas(n+m,m,p));
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: