zoukankan      html  css  js  c++  java
  • Lucas定理及其应用

    概述:

    (Lucas) 定理用于求解大组合数取模的问题,其中 (p) 必须为素数。

    (Lucas) 定理内容如下:

    [C_{n}^{m}=C_{(n/p)}^{(m/p)} * C_{(n\%p)}^{(m\%p)}(mod p) ]

    观察上述表达式,可知 (n\%p)(m\%p) 一定是小于 (p) 的数,可以直接求解。
    (C_{(n/p)}^{(m/p)}) 可以继续用 (Lucas) 定理求解,这也就要求 (p) 的范围不能够太大,一般在 (1e5) 左右。
    边界条件:当 (m=0) 的时候,返回 (1)
    复杂度:(O(logn+p))

    模板代码【P3807】:

    //1≤n,m,p≤10^5,1≤T≤10,p为素数
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll power(ll a,ll b,ll p)
    {
        ll res=1;
        while(b)
        {
            if(b&1)
                res=res*a%p;
            a=a*a%p;
            b>>=1;
        }
        return res%p;
    }
    ll C(ll n,ll m,ll p)
    {
        if(m>n)
            return 0;
        ll a=1,b=1;
        m=min(m,n-m);
        while(m)
        {
            a=a*(n-m+1)%p;
            b=b*m%p;
            m--;
        }
        return a*power(b,p-2,p);
    }
    ll Lucas(ll n,ll m,ll p)
    {
        return m?C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p:1;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        ll n,m,p;
        while(t--)
        {
            scanf("%lld%lld%lld",&n,&m,&p);
            printf("%lld
    ",Lucas(n+m,m,p));
        }
        return 0;
    }
    
    

    具体证明

  • 相关阅读:
    131. 分割回文串
    博客开通第二十七天
    博客开通第三十八天
    博客开通第56天
    博客开通第三十三天
    博客开通第61天
    博客开通第62天
    博客开通第二十六天
    博客开通第四十七天
    博客开通第63天
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/12642250.html
Copyright © 2011-2022 走看看