P4720 模板扩展卢卡斯定理/exLucas(无讲解,纯记录模板)

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4720 模板扩展卢卡斯定理/exLucas(无讲解,纯记录模板)相关的知识,希望对你有一定的参考价值。

P4720 【模板】扩展卢卡斯定理/exLucas

题意:

C n m   m o d   p C_{n}^{m}\\bmod p Cnmmodp
对于 100% 的数据,1≤m≤n≤1018,2≤p≤106,不保证 p 是质数。

题解:

模板题,单纯写本文章记录板子

代码:

#include <cstdio>
using namespace std;

typedef long long ll;

ll mod;

void exgcd(ll a, ll b, ll& x, ll& y)
{
    if (!b) {
        x= 1, y= 0;
        return;
    }
    exgcd(b, a % b, y, x);
    y-= a / b * x;
    return;
}

inline ll inv(ll n, ll p)
{
    ll x, y;
    exgcd(n, p, x, y);
    return (x + p) % p;
}

ll qpow(ll base, ll p, ll mod)
{
    ll ret= 1;
    for (; p; p>>= 1, base= base * base % mod)
        if (p & 1)
            ret= ret * base % mod;
    return ret;
}

ll CRT(int n, ll* a, ll* m)
{
    ll M= 1, ret= 0;
    for (ll i= 1; i <= n; i++)
        M*= m[i];
    for (ll i= 1; i <= n; i++) {
        ll w= M / m[i];
        ret= (ret + a[i] * w % mod * inv(w, m[i]) % mod) % mod;
    }
    return (ret + mod) % mod;
}

ll calc(ll n, ll q, ll qk)
{
    if (!n)
        return 1;
    ll ret= 1;
    for (ll i= 1; i <= qk; i++)
        if (i % q)
            ret= ret * i % qk;
    ret= qpow(ret, n / qk, qk);
    for (ll i= n / qk * qk + 1; i <= n; i++)
        if (i % q)
            ret= ret * (i % qk) % qk;
    return ret * calc(n / q, q, qk) % qk;
}

ll multiLucas(ll n, ll m, ll q, ll qk)
{
    int cnt= 0;
    for (ll i= n; i; i/= q)
        cnt+= i / q;
    for (ll i= m; i; i/= q)
        cnt-= i / q;
    for (ll i= n - m; i; i/= q)
        cnt-= i / q;
    return qpow(q, cnt, qk) * calc(n, q, qk) % qk * inv(calc(m, q, qk), qk) % qk * inv(calc(n - m, q, qk), qk) % qk;
}

ll exLucas(ll n, ll m, ll p)
{
    int cnt= 0;
    ll qk[20], a[20]; //存放所有的 q^k 和待合并答案的结果
    for (ll i= 2; i * i <= p; ++i) //质因数分解
    {
        if (p % i == 0) {
            qk[++cnt]= 1;
            while (p % i == 0)
                qk[cnt]*= i, p/= i;
            a[cnt]= multiLucas(n, m, i, qk[cnt]);
        }
    }
    if (p > 1)
        qk[++cnt]= p, a[cnt]= multiLucas(n, m, p, p);
    return CRT(cnt, a, qk); //CRT 合并答案
}

int main()
{
    ll n, m, p;
    scanf("%lld %lld %lld", &n, &m, &p);
    mod= p;
    printf("%lld\\n", exLucas(n, m, p));
    return 0;
}

以上是关于P4720 模板扩展卢卡斯定理/exLucas(无讲解,纯记录模板)的主要内容,如果未能解决你的问题,请参考以下文章

P4720 模板扩展卢卡斯

luogu P3807 卢卡斯定理 模板

[模板] 数学基础:逆元/exGCD/exCRT/Lucas定理/exLucas

Unknown Treasure (卢卡斯 + 孙子定理, 模板题)

P3807 模板卢卡斯定理

洛谷 P3807 模板卢卡斯定理