• 扩展卢卡斯定理


    LuoguP4720

    先来一篇大佬的博客 Fading 的博客

    然后如果你能认真研读上面大佬的博客的话,应该就比较轻松了,我比较蒟蒻,还是不要多说的好=w=

    Code:

      1 #include <bits/stdc++.h>
      2 #define ll long long
      3 using namespace std;
      4 const int N = 1007;
      5 ll n, m, p;
      6 ll a[N], b[N];
      7 void exgcd(ll a, ll b, ll &x, ll &y) {//用于求逆元 
      8     if (b == 0) {
      9         x = 1;
     10         y = 0;
     11         return;
     12     }
     13     exgcd(b, a % b, x, y);
     14     ll t = x;
     15     x = y;
     16     y = t - a / b * y;
     17 }
     18 ll inv(ll a, ll p) {//求a在p意义下的逆元 
     19     ll x, y;
     20     exgcd(a, p, x, y);
     21     return (x + p) % p;//保证其为非负 
     22 }
     23 ll mul(ll a, ll b, ll p) {//龟速乘防爆 
     24     ll re = 0;
     25     a %= p;
     26     b %= p;
     27     for (; b; b >>= 1) {
     28         if (b & 1) {
     29             re = (re + a) % p;
     30         }
     31         a = (a + a) % p;
     32     }
     33     return re;
     34 }
     35 ll pw(ll x, ll y, ll p) {//快速幂 
     36     ll re = 1;
     37     x %= p;
     38     for (; y; y >>= 1) {
     39         if (y & 1) {
     40             re = re * x % p;
     41         }
     42         x = x * x % p;
     43     }
     44     return re;
     45 }
     46 ll fac(ll n, ll p, ll pk) {//求n! % p**k 
     47     if (n == 0) {
     48         return 1;
     49     }
     50     ll rou = 1;//求循环节 
     51     ll rem = 1;//求余项 
     52     for (ll i = 2; i <= pk; i++) {
     53         if (i % p) {
     54             rou = rou * i % pk;
     55         }
     56     }
     57     rou = pw(rou, n / pk, pk);
     58     for (ll i = pk * (n / pk); i <= n; i++) {
     59         if (i % p) {
     60             rem = rem * (i % pk) % pk;
     61         }
     62     }
     63     return fac(n / p, p, pk) * rou % pk * rem % pk;
     64 }
     65 ll G(ll n, ll p) {//算一个次幂 
     66     if (n < p) {
     67         return 0;
     68     }
     69     return G(n / p, p) + (n / p);
     70 }
     71 ll C_pk(ll n, ll m, ll p, ll pk) {//求组合数C(n,m) % p**k 
     72     ll f = fac(n, p, pk);
     73     ll inv1 = inv(fac(m, p, pk), pk);
     74     ll inv2 = inv(fac(n - m, p, pk), pk);
     75     ll mi = pw(p, G(n, p) - G(m, p) - G(n - m, p), pk);
     76     return f * inv1 % pk * inv2 % pk * mi % pk;
     77 }
     78 ll exlucas(ll n, ll m, ll p) {//拓展卢卡斯定理 
     79     ll re = p, tot = 0;
     80     for (ll i = 2; i * i <= p; i++) {
     81         if (re % i == 0) {
     82             ll pk = 1;
     83             while (re % i == 0) {
     84                 pk *= i;
     85                 re /= i;
     86             }
     87             a[++tot] = C_pk(n, m, i, pk);//先将p分解,然后分别记下方程组 
     88             b[tot] = pk;
     89         }
     90     }
     91     if (re != 1) {
     92         a[++tot] = C_pk(n, m, re, re);
     93         b[tot] = re;
     94     }
     95     ll ans = 0;
     96     for (ll i = 1; i <= tot; i++) {//再用中国剩余定理合并求出答案 
     97         ll t = p / b[i];
     98         ll inv1 = inv(t, b[i]);
     99         ans = (ans + a[i] * t % p * inv1 % p) % p;
    100     }
    101     return ans;
    102 }
    103 int main () {
    104     scanf("%lld%lld%lld", &n, &m, &p);
    105     printf("%lld
    ", exlucas(n, m, p));
    106     return 0;
    107 }
    View Code
  • 相关阅读:
    linux ftp启用和停用及vsftpd安装 ssh 启用和停用命令及ssh的安装
    linux 网络命令
    printf的使用
    Shell echo命令
    shell脚本之文件操作
    shell脚本之字符串运算的使用
    linux的计划任务操作
    系统操作有关的命令
    shell脚本之 operater.sh 算术运算符;比较运算符;布尔运算符;逻辑与或非运算符;字符串运算符的使用
    shell脚本的参数传递使用
  • 原文地址:https://www.cnblogs.com/Sundial/p/11830563.html
Copyright © 2020-2023  润新知