lucas定理 学习笔记

lucas定理 学习笔记

文章目录

  • lucas定理 学习笔记
    • 介绍
    • combination
      • 题目描述
      • 输入格式
      • 输出格式
      • 样例
        • 输入样例1
        • 输出样例2
    • 分析
    • code
  • 扩展lucas

介绍

lucas定理用于解决形如 C n m m o d    p ( p ∈ p r i m e ) C_n^m \mod p (p\in prime) Cnmmodp(pprime) 的问题。

n , m n,m n,m p p p 进制来表示为: ( n a n a − 1 ⋯ n 0 ) p , ( m a m a − 1 ⋯ m 0 ) p (n_an_{a-1}\cdots n_0)_p , (m_am_{a-1}\cdots m_0)_p (nana1n0)p,(mama1m0)p

则:
C n m = C n a m a ∗ C n a − 1 m a − 1 ⋯ C n 0 n 0 C_n^m = C_{n_a}^{m_a}*C_{n_{a-1}}^{m_{a-1}}\cdots C_{n_0}^{n_0} Cnm=CnamaCna1ma1Cn0n0
例如下面这道题 oj

combination

题目描述

LMZ有n个不同的基友,他每天晚上要选m个一起玩,而且要求每天晚上的选择都不一样。那么LMZ能够持续多少个这样的夜晚呢?当然,LMZ的一年有10007天,所以他想知道答案mod 10007的值。(1<=m<=n<=200,000,000)

输入格式

第一行一个整数t,表示有t组数据。(t<=200) 接下来t行每行两个整数n, m,如题意。

输出格式

T行,每行一个数,为C(n, m) mod 10007的答案。

样例

输入样例1

4
5 1
5 2
7 3
4 2

输出样例2

5
10
35
6

分析

显然,答案就是: C n m m o d    10007 C_n^m \mod 10007 Cnmmod10007

但是我们的 f a c [ ] , i n v [ ] fac[] , inv[] fac[],inv[] 开不了200,000,000,

所以我们就可以用 lucas 定理减小空间

code

#include 
#define LL long long
#define fu(x , y , z) for (int x = y ; x <= z ; x ++)
#define fd(x , y , z) for (int x = y ; x >= z ; x --)
using namespace std;
const int mod = 10007;
LL fac[mod + 5] , inv[mod + 5] , n , m;
LL ksm (LL x , LL y) {
    if(!y)
        return 1;
    long long z = ksm (x , y / 2);
    z = z * z % mod;
    if (y & 1)
        z = z * x % mod;
    return z; 
}
void pre () {
    fac[0] = fac[1] = 1;
    for(int i = 2 ; i <= mod - 1 ; i++)
        fac[i] = fac[i - 1] * i % mod;
    inv[mod - 1] = ksm (fac[mod - 1] , mod - 2);
    for (int i = mod - 2 ; i >= 0 ; i --)
        inv[i] = inv[i + 1] * (i + 1) % mod;
}
LL C (LL x , LL y) {
    if (x < y) return 0;
    if (!y || x == y) return 1;
    return fac[x] * inv[y] % mod * inv[x - y] % mod;
}
LL lucas (LL x , LL y) {
    if (x < y) return 0;
    if (!y) return 1;
    if (x < mod && y < mod) return C (x , y);
    return lucas (x / mod , y / mod) * C (x % mod , y % mod) % mod;
}
int main () {
    pre ();
    int T;
    scanf ("%d" , &T);
    while (T --) {
        scanf ("%lld%lld" , &n , &m);
        printf ("%lld\n" , lucas (n , m));
    }
}

扩展lucas

未完待续

你可能感兴趣的:(数学,学习,笔记,算法)