zoukankan      html  css  js  c++  java
  • [Codeforces 100633J]Ceizenpok’s formula

    Description

    题库链接

    [C_n^m mod p]

    (1leq mleq nleq 10^{18},2leq pleq 1000000)

    Solution

    一般的 (Lucas) 是在模数 (p) 是质数的条件下适用的。我们来考虑 (p) 不是质数的条件。

    我们对 (p) 进行唯一分解,记 (p=p_1^{k_1}p_2^{k_2}cdots p_q^{k_q}) ,由于形同 (p_i^{k_i}) 的部分是互质的,显然我们可以用 (CRT) 合并。

    列出方程组: [left{ egin{array}{c} ansequiv c_1pmod {{p_1}^{k_1}}\ ansequiv c_2pmod {{p_2}^{k_2}}\ ...\ ansequiv c_qpmod {{p_q}^{k_q}}\ end{array} ight.] ,对于每个 (c_i) ,表示 (C_n^m)(mod p_i^{k_i}) 下的结果。由解的唯一性,我们可以证明这个 (ans) 就是我们要求的。
    根据 (C_n^m=frac{n!}{m!(n-m)!}) 我们只要求出 (n!mod p_i^{k_i},m!mod p_i^{k_i},(n-m)!mod p_i^{k_i}) ,再用逆元的那套理论就可以求 (c_i) 了。

    考虑如何求 (n!mod p_i^{k_i}) 。容易发现 (n!=left(prodlimits_{j=1}^n j^{[p_i mid j]} ight)cdotleft(p_i^{leftlfloorfrac{n}{p_i} ight floor} ight)cdotleft(leftlfloorfrac{n}{p_i} ight floorlarge! ight)) 上述式子分为三个部分,第一个部分显然在模 (p_i^{k_i}) 下,是以 (p_i^{k_i}) 为周期的。可以周期内找循环节算,周期外的暴力算;第二部分可以直接算;第三部分可以递归求解。

    另外注意的是求组合逆元的时候,存在阶乘中的某一个数可能还有 (p_i) 这个质因子,不能直接算。直接把 (p_i) 全部提出来,最后求完逆元后再补回去。求 (n!) 内质因子 (p) 的个数可以用 (sumlimits_{i=1}^{+infty} leftlfloorfrac{n}{p^i} ight floor) 来求。

    Code

    //It is made by Awson on 2018.2.10
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    void read(LL &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    LL n, m, p;
    
    LL quick_pow(LL a, LL b, LL p) {
        LL ans = 1;
        while (b) {
        if (b&1) ans = ans*a%p;
        b >>= 1, a = a*a%p;
        }
        return ans;
    }
    void ex_gcd(LL a, LL b, LL &x, LL &y) {
        if (b == 0) {x = 1, y = 0; return; }
        ex_gcd(b, a%b, x, y);
        LL t = x; x = y, y = t-a/b*y;
    }
    LL inv(LL a, LL p) {
        LL x, y; ex_gcd(a, p, x, y);
        return (x%p+p)%p;
    }
    LL mul(LL n, LL pi, LL pk) {
        if (!n) return 1;
        LL ans = 1;
        for (int i = 2; i <= pk; i++) if (i%pi != 0) ans = ans*i%pk;
        ans = quick_pow(ans, n/pk, pk);
        for (int i = 2; i <= n%pk; i++) if (i%pi != 0) ans = ans*i%pk;
        return ans*mul(n/pi, pi, pk)%pk;
    }
    LL C(LL n, LL m, LL pi, LL pk, LL p) {
        LL a = mul(n, pi, pk), b = mul(m, pi, pk), c = mul(n-m, pi, pk);
        LL k = 0;
        for (LL i = n; i; i /= pi) k += i/pi;
        for (LL i = m; i; i /= pi) k -= i/pi;
        for (LL i = n-m; i; i /= pi) k -= i/pi;
        return a*inv(b, pk)%pk*inv(c, pk)%pk*quick_pow(pi, k, pk)%pk;
    }
    LL ex_lucas(LL n, LL m, LL p) {
        LL ans = 0;
        for (LL i = 2, x = p; i <= x; i++)
        if (x%i == 0) {
            LL k = 1; while (x%i == 0) k *= i, x /= i;
            (ans += C(n, m, i, k, p)*(p/k)%p*inv(p/k, k)%p) %= p;
        }
        return ans;
    }
    void work() {
        read(n), read(m), read(p);
        writeln(ex_lucas(n, m, p));
    }
    int main() {
        work();
        return 0;
    }
  • 相关阅读:
    下拉菜单的option的value属性值问题
    GDAL1.9.1 IN VS2008 C#中的编译及使用
    多表连接 去重
    【示例代码】HTML+JS 画图板源码分享
    Winet API 支持HTTPP/SOCKS代理
    入门Html
    关于CDC在非控件类中的使用
    The document "ViewController.xib" could not be opened. Could not read archive.
    华为的一道题
    [置顶] WEBSOKET服务器搭建
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8438995.html
Copyright © 2011-2022 走看看