zoukankan      html  css  js  c++  java
  • lucas定理

    lucas定理

    快速求组合数取模

    注:mod是少于1e5的质数

    核心代码

    //C(n, m) % mod
    LL lucas(LL n, LL m, LL mod) {
        if(m == 0) return 1LL;
        return (C(n % mod, m % mod, mod) * lucas(n / mod, m / mod, mod)) % mod;
    }
    //关于C(n % mod, m % mod) % mod,可以这样求
    //第一种
    LL C(LL n, LL m, LL mod) {
       	LL inv[maxn];
       	inv[1] = 1;
        LL f = 1;
        for(int i = n - m + 1; i <= n; i++) f = f * i % mod;//(n-m+1)*(n-m+2)*...*n
        for(int i = 2; i <= m; i++) inv[i] = (mod - mod / i) * 1LL * inv[mod % i] % mod;//打表1~m关于mod的逆元
        for(int i = 2; i <= m; i++) inv[i] = inv[i] * inv[i-1] % mod;//m!关于mod的逆元
        return (f * inv[m]) % mod;
    }
    //第二种
    LL power(LL a, LL b, LL p) {
        LL ret = 1;
        while(b) {
            if(b & 1) ret = ret * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return ret;
    }
    LL f[100010];//f[i]表示 i! % p
    LL C(LL n, LL m, LL p) {
        if(n < m) return 0;
        return (f[n] * power(f[m], p-2, p)) % p * power(f[n-m], p-2, p) % p;
    }
    

    P3807 【模板】卢卡斯定理

    #include <cstdio>
    typedef long long LL;
    LL C(LL n, LL m, LL p) {
        LL inv[100010];
        inv[1] = 1;
        LL f = 1;
        for(int i = n - m + 1; i <= n; i++) f = f * i % p;
        for(int i = 2; i <= m; i++) inv[i] = (p - p / i) * 1LL * inv[p % i] % p;
        for(int i = 2; i <= m; i++) inv[i] = inv[i] * inv[i-1] % p;
        return (f * inv[m]) % p;
    }
    LL lucas(LL n, LL m, LL p) {
        if(m == 0) return 1LL;
        return (C(n % p, m % p, p) * lucas(n / p, m / p, p)) % p;
    }
    int main() {
        int t;
        scanf("%d", &t);
        while(t--) {
            LL n, m, p;
            scanf("%lld %lld %lld", &m, &n, &p);
            n += m;
            printf("%lld
    ", lucas(n, m, p));
        }
        return 0;
    }
    

    牛牛与组合数学

    #include <cstdio>
    #include <cstring>
    typedef long long LL;
    LL inv[150000];
    LL mod[10] = {88897 ,58787 ,125453 , 7853 , 78569 ,145267 ,25867 ,105899 ,8803,4591};
    LL C(LL n, LL m, LL p) {
        if(n < m) return 0;
        LL f = 1;
        inv[1] = 1;
        for(int i = n-m+1; i <= n; i++) f = f * i % p;
        for(int i = 2; i <= m; i++) inv[i] = (p - p / i) * 1LL * inv[p % i] % p;
        for(int i = 2; i <= m; i++) inv[i] = inv[i] * inv[i-1] % p;
        return ((f * inv[m]) % p);
    }
    LL lucas(LL n, LL m, LL p) {
        if(m == 0) return 1;
        return (C(n % p, m % p, p) * lucas(n / p, m / p, p)) % p;
    }
    char s[4000010];
    int main() {
        LL n, m;
        scanf("%lld %lld %s", &n, &m, s);
        int flag = 0;
        int ns = strlen(s);
        for(int j = 0; j < 10; j++) {
            LL num = 0;
            for(int i = 0; i < ns; i++) {
                num = num * 10 + (s[i] - '0');
                num = num % mod[j];
            }
            LL num2 = lucas(n, m, mod[j]);
            if(num != num2) {
                flag = 1;
                printf("No!
    ");
                break;
            }
        }
        if(flag == 0) printf("Yes!
    ");
        return 0;
    }
    

    Saving Beans HUD 3037

    松鼠有不多于m颗松果(0~m),他决定放到n棵树下(有些树可以不放),问有多少种方案。结果取模p

    根据插板法,(sum_{i=0}^mC_{n+m-1}^{n-1}) = (C_{n-1}^{n-1}) + (C_n^{n-1}) +...+ (C_{n+m-1}^{n-1})

    = (C_n^n) + (C_n^{n-1}) +...+ (C_{n+m-1}^{n-1})

    = (C_{n+1}^n) + (C_{n+1}^{n-1}) +... + (C_{n+m-1}^{n-1})

    =(C_{n+m}^n)

    (组合数推导公式:(C_n^m) = (C_{n-1}^m) + (C_{n-1}^{m-1}))

    这里用上面第一种求C(LL a, LL b, LL p)会wa,我搞不懂QAQ

    #include <cstdio>
    typedef long long LL;
    LL power(LL a, LL b, LL p) {
        LL ret = 1;
        while(b) {
            if(b & 1) ret = ret * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return ret;
    }
    LL f[100010];
    LL C(LL n, LL m, LL p) {
        if(n < m) return 0;
        return (f[n] * power(f[m], p-2, p)) % p * power(f[n-m], p-2, p) % p;
    }
    LL lucas(LL n, LL m, LL p) {
        if(m == 0) return 1LL;
        return (C(n % p, m % p, p) * lucas(n / p, m / p, p)) % p;
    }
    int main() {
        int t;
        scanf("%d", &t);
        while(t--) {
            LL n, m, p;
            scanf("%lld %lld %lld", &n, &m, &p);
            n += m;
            f[0] = f[1] = 1;
            for(int i = 2; i < p; i++) f[i] = f[i-1] * i % p;
            printf("%lld
    ", lucas(n, m, p));
        }
        return 0;
    }
    
    
  • 相关阅读:
    从零开始学Go之函数(一):匿名函数与闭包
    从零开始学Go之容器(四):列表
    从零开始学Go之容器(三):映射
    从零开始学Go之容器(二):切片
    从零开始学Go之容器(一):数组
    从零开始学Go之基本(五):结构体
    从零开始学Go之基本(四):流程控制语句
    从零开始学Go之基本(三):类型转换与常量
    Java 单例设计模式
    Java 数组
  • 原文地址:https://www.cnblogs.com/fanshhh/p/12632527.html
Copyright © 2011-2022 走看看