zoukankan      html  css  js  c++  java
  • 数学:拓展Lucas定理

    拓展Lucas定理解决大组合数取模并且模数为任意数的情况

    大概的思路是把模数用唯一分解定理拆开之后然后去做

    然后要解决的一个子问题是求模质数的k次方

    将分母部分转化成逆元再去做就好了

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 100000 + 10;
     4 typedef long long LL;
     5 
     6 LL Pow(LL n, LL m, LL mod) {
     7     LL ans = 1;
     8     while(m > 0) {
     9         if(m & 1) ans = (LL)ans * n % mod;
    10         n = (LL)n * n % mod; m >>= 1;
    11     }
    12     return ans;
    13 }
    14 LL Pow(LL n,LL m) {
    15     LL ans = 1;
    16     while(m > 0) {
    17         if(m & 1) ans = ans * n;
    18         n = n * n; m >>= 1;
    19     }
    20     return ans;
    21 }
    22 LL x, y;
    23 LL exgcd(LL a, LL b) {
    24     if(a == 0) {
    25         x = 0, y = 1;
    26         return b;
    27     }LL r = exgcd(b%a, a);
    28     LL t = x; x = y - (b/a)*x; y = t;
    29     return r;
    30 }
    31 LL rev(LL a, LL b) { exgcd(a, b); return ((x % b) + b) % b; }
    32 LL Calc(LL n, LL p, LL t) {
    33     if(n == 0) return 1;
    34 
    35     LL s = Pow(p, t), k = n / s, tmp = 1;
    36     for(LL i=1; i<=s; i++) if(i % p) tmp = (LL)tmp * i % s;
    37 
    38     LL ans = Pow(tmp, k, s);
    39     for(LL i=s*k + 1; i<=n; i++) if(i % p) ans = (LL)ans * i % s;
    40 
    41     return (LL)ans * Calc(n / p, p, t) % s;
    42 }
    43 LL C(LL n, LL m, LL p, LL t) {
    44     LL s = Pow(p, t), q = 0;
    45     for(LL i=n; i; i/=p) q += i / p;
    46     for(LL i=m; i; i/=p) q -= i / p;
    47     for(LL i=n-m; i; i/=p) q -= i / p;
    48 
    49     LL ans = Pow(p, q);
    50     LL a = Calc(n, p, t), b = Calc(m, p, t), c = Calc(n-m, p, t);
    51     return (LL)(ans * a * rev(b, s) * rev(c, s)) % s;
    52 }
    53 LL China(LL A[], LL M[], LL cnt) {
    54     LL ans = 0, m, n = 1;
    55     for(LL i=1; i<=cnt; i++) n *= M[i];
    56     for(LL i=1; i<=cnt; i++) {
    57         m = n / M[i];
    58         exgcd(M[i], m);
    59         ans = (ans + (LL)y * m * A[i]) % n;
    60     }
    61     return (ans + n) % n;
    62 }
    63 LL A[maxn], M[maxn], cnt;
    64 LL Lucas(LL n, LL m, LL mod) {
    65     for(LL i=2; i*i <= mod; i++) if(mod % i == 0) {
    66         LL t = 0;
    67         while(mod % i == 0) t++, mod /= i;
    68         M[++cnt] = Pow(i, t);
    69         A[cnt] = C(n, m, i, t);
    70     }if(mod > 1) {
    71         M[++cnt] = mod;
    72         A[cnt] = C(n, m, mod, 1);
    73     }
    74     return China(A, M, cnt);
    75 }
    76 LL n, k, p;
    77 int main() {
    78     cin >> n >> k >> p;
    79     cout << Lucas(n, k, p) << endl;
    80     return 0;
    81 }

    然后补充一个内容,线性时间复杂度内求出所有的逆元

    A[i] = -(p / i) * A[p % i];
  • 相关阅读:
    easyui accordion—手风琴格子始终展开和多个格子展开
    55分钟学会正则表达式
    解决github push错误The requested URL returned error: 403 Forbidden while accessing
    浅谈github页面域名绑定
    HighChartS cpu利用率动态图(Java版)
    easyUI——datebox验证和自定义取消按钮
    Linux下常用压缩格式的压缩与解压方法
    EasyUI修改DateBox和DateTimeBox的默认日期格式
    Highcharts的基本属性和方法详解
    Highcharts的基本属性和方法详解
  • 原文地址:https://www.cnblogs.com/aininot260/p/9709238.html
Copyright © 2011-2022 走看看