P4720 模板扩展卢卡斯

Posted olinr

tags:

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

(color{#0066ff}{ 题目描述 })

(C_n^m mod{p})

其中 (C) 为组合数。

(color{#0066ff}{输入格式})

一行三个整数?(n,m,p)?,含义由题所述。

(color{#0066ff}{输出格式})

一行一个整数,表示答案

(color{#0066ff}{输入样例})

5 3 3
    
    
666 233 123456

(color{#0066ff}{输出样例})

1
    
    
61728

(color{#0066ff}{数据范围与提示})

(1≤m≤n≤10^{18}),(2≤p≤1000000)?,不保证?(p)?是质数

(color{#0066ff}{ 题解 })

简单来说,这个东西就是吧p分解成(prod p^c)

求出组合数mod(p^c)的值然后用CRT合并

这里要用到快速阶乘

比如19的阶乘mod(3^2)

(1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19)

 把所有3的倍数都提出一个3

(3^6*6!*(1*2*4*5*7*8)*(10*11*13*14*16*17)*19)

发现分解成了一个快速幂,一个子问题阶乘,后面的还有循环节

递归处理即可

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
LL ksm(LL x, LL y, LL mod) {
    LL re = 1LL;
    while(y) {
        if(y & 1) re = re * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return re;
}
LL exgcd(LL a, LL b, LL &x, LL &y) {
    if(!b) return x = 1, y = 0, a;
    LL r = exgcd(b, a % b, x, y);
    LL t = x - a / b * y;
    return x = y, y = t, r;
}
LL inv(LL x, LL mod) {
    LL p, q;
    exgcd(x, mod, p, q);
    return ((p % mod) + mod) % mod;
}
LL n, m, p;
//乘了p/mod是为了保证其它式子不受影响,再乘当前的逆元保证的事当前式子不受影响
LL CRT(LL b, LL mod) { return b * inv(p / mod, mod) % p * (p / mod) % p; }
LL fac(LL x, LL r, LL rk) {
    //0的阶乘为1
    if(!x) return 1;
    LL ans = 1;
    //单个循环的ans
    for(LL i = 1; i <= rk; i++) if(i % r) ans = ans * i % rk;
    //有循环节,快速幂一下
    ans = ksm(ans, x / rk, rk);
    //最后剩余的可能不足一个循环节的部分
    for(LL i = 1; i <= x % rk; i++) if(i % r) ans = ans * i % rk;
    //子问题(快速幂写在了外面,方便)
    return ans * fac(x / r, r, rk) % rk;
}
LL C(LL x, LL y, LL r, LL rk) {
    LL X = fac(x, r, rk), Y = fac(y, r, rk), XY = fac(x - y, r, rk);
    LL ans = 0;
    for(LL i = x; i; i /= r) ans += i / r;
    for(LL i = y; i; i /= r) ans -= i / r;
    for(LL i = x - y; i; i /= r) ans -= i / r;
    return X * inv(Y, rk) % rk * inv(XY, rk) % rk * ksm(r, ans, rk) % rk;
}
LL exlucas() {
    LL res = p, ans = 0;
    for(LL i = 2; i * i <= p; i++) {
        if(res % i == 0) {
            LL tot = 1;
            while(res % i == 0) tot *= i, res /= i;
            (ans += CRT(C(n, m, i, tot), tot)) %= p;
        }
    }
    if(res > 1) (ans += CRT(C(n, m, res, res), res)) %= p;
    return ans;
}
int main() {
    n = in(), m = in(), p = in();
    printf("%lld
", exlucas());
    return 0;
}

以上是关于P4720 模板扩展卢卡斯的主要内容,如果未能解决你的问题,请参考以下文章

luogu P3807 卢卡斯定理 模板

P2183 [国家集训队]礼物(扩展卢卡斯)

一本通 P1806 计算器

洛谷 P3807 模板卢卡斯定理

洛谷——P3807 模板卢卡斯定理

P3807 模板卢卡斯定理