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

    大致意思就是求组合数C(n , m) % p的值, p为一个偶数

    可以将组合数的n 和 m都理解为 p 进制的表示

    n  = ak*p^k + a(k-1)*p^(k-1) + ... + a1*p + a0

    m = bk*p^k + b(k-1)*p^(k-1) + ... + b1*p + b0

    然后C(n,m)%p = C(ak , bk) * C(a(k-1) , b(k-1)) * ... * C(a1 , b1) * C(a0 , b0) % p

    当然这其中出现 ai < bi的情况那直接视为乘以了 0

    其他情况都是正常的组合数计算

    因为p为素数,取模的过程求逆元就是利用欧拉定理来求解

    a^(-1) = a^(p-2) (mod p) 

    那么只要快速幂求a^(p-2) % p的值就行了 , 那么组合数C(ai , bi) 就可以算出来了

    HDU 4349 求C(n , i)中 0<=i<=n 中多少个可以使C(n , i)为奇数

     这里先将n转化为二进制表示,因为C(n,m)%p = C(ak , bk) * C(a(k-1) , b(k-1)) * ... * C(a1 , b1) * C(a0 , b0) % p

    那么只会出现ai = 0 , 1 bi = 0 , 1的情况

    那么只有ai=0 , bi = 1 才是C(ai , bi) = 0为偶数,其他时候都是奇数,那只要枚举每一位保证那一位出现的数字可能不超过n对应的二进制位即可

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main() {
     5     int n;
     6     while(~scanf("%d" , &n)){
     7         int ret = 1;
     8         while(n){
     9             ret = ret*((n&1)+1);
    10             n>>=1;
    11         }
    12         printf("%d
    ",ret);
    13     }    
    14     return 0;
    15 }

    HDU 3037 一道比较裸的lucas定理的题目

    求C(n+m , n)%p的值

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 
     5 int q_pow(int a , int b , int p)
     6 {
     7     ll ret = 1;
     8     while(b){
     9         if(b&1) ret = ret*a%p;
    10         a = (ll)a*a%p;
    11         b>>=1;
    12     }
    13     return ret;
    14 }
    15 
    16 int C(int a , int b , int p)
    17 {
    18     if(b==0) return 1;
    19     if(a<b) return 0;
    20     if(a==b) return 1;
    21     int s=1 , t=1;
    22     for(int i=1 ; i<=b ; i++) s=(ll)s*(a-i+1)%p;
    23     for(int i=1 ; i<=b ; i++) t=(ll)t*i%p;
    24     //cout<<"C: "<<a<<" "<<b<<" "<<p<<" "<<s<<" "<<t<<endl;
    25     return (ll)s*q_pow(t , p-2 , p)%p;
    26 }
    27 
    28 int lucas(int a, int b,int p)
    29 {
    30     //cout<<"in: "<<a<<" "<<b<<" "<<p<<endl;
    31     if(b==0) return 1;
    32     if(a<b) return 0;
    33     if(a==b) return 1;
    34     //cout<<"en: "<<C(a%p , b%p , p)<<endl;
    35     return (ll)C(a%p , b%p , p)*lucas(a/p , b/p , p)%p;
    36 }
    37 
    38 int main() {
    39     //freopen("in.txt" , "r" , stdin);
    40     int n;
    41     scanf("%d" , &n);
    42     while(n--){
    43         int a , b , p;
    44         scanf("%d%d%d", &a , &b , &p);
    45         printf("%d
    " , lucas(a+b,a,p));
    46     }    
    47     return 0;
    48 }
  • 相关阅读:
    【NOIP 2003】 加分二叉树
    【POJ 1655】 Balancing Act
    【HDU 3613】Best Reward
    【POJ 3461】 Oulipo
    【POJ 2752】 Seek the Name, Seek the Fame
    【POJ 1961】 Period
    【POJ 2406】 Power Strings
    BZOJ3028 食物(生成函数)
    BZOJ5372 PKUSC2018神仙的游戏(NTT)
    BZOJ4836 二元运算(分治FFT)
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4796483.html
Copyright © 2011-2022 走看看