zoukankan      html  css  js  c++  java
  • 卢卡斯(Lucas)定理

    问题

    洛谷 题目地址

    给你正整数 (n,m,p),其中 (p) 是质数。求 (dbinom{n}{m} \% p)(dbinom{n}{m}) 是组合数,表示 (n) 选出 (m))。

    Lucas定理结论

    (p) 是质数,则对于任意整数 (1 le m le n),有:

    [dbinom{n}{m} equiv dbinom{n\%p}{m\%p} * dbinom{lfloor n/p floor}{lfloor m/p floor} pmod{p} ]

    另一种形式:

    (n=sum_{i=0}^k n_i*p^i,m=sum_{i=0}^k m_i*p^i)(相当于把 (n,m) 写成 (p) 进制数),那么有:

    [dbinom{n}{m} equiv prod_{i=0}^k dbinom{n_i}{m_i} pmod{p} ]

    很显然两种形式意义相同,我们直接证明后面这个式子。

    证明

    前置知识:多项式同余

    前置知识:二项式定理

    推导:

    [ecause (1+x)^p = sum_{i=0}^p dbinom{p}{i} 1^{p-i}*x^i = sum_{i=0}^p dbinom{p}{i} x^i ]

    [ herefore (1+x)^p equiv sum_{i=0}^p dbinom{p}{i} x^i pmod{p} ]

    首项尾项拎出来,因为中间的项都至少含有一个因子 (p),所以在 (mod p) 意义下为零,因此有:

    [(1+x)^p equiv 1+x^p pmod{p} ]

    利用上面这个结论:

    [ecause (1+x)^n = prod_{i=0}^k (1+x)^{n_i*p^i} ]

    [ herefore (1+x)^n equiv prod_{i=0}^k (1+x^{p^i})^{n_i} pmod{p} ]

    我们又知道 (dbinom{n}{m}) 表示 ((1+x)^n) 的展开式中 (x^m) 的系数。

    (dbinom{n_i}{m_i}) 表示 ((1+x^{p^i})^{n_i}) 的展开式中 (x^{m_i*p^i})

    (dbinom{n_0}{m_0} x^{m_0*p^0},...,dbinom{n_k}{m_k} x^{m_k*p^k}) 相乘,可以得到 (dbinom{n_0}{m_0}*...*dbinom{n_k}{m_k} x^m = (prod_{i=0}^k dbinom{n_i}{m_i}) x^m)

    回到前面这个同余式,根据多项式同余定理,两个式子同余,那么就有两个多项式的 (x^m) 这项的系数同余,于是就有:

    [dbinom{n}{m} equiv prod_{i=0}^k dbinom{n_i}{m_i} pmod{p} ]

    证毕。

    Code

    Talk is cheap.Show me the code.

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    inline int read() {
    	int x=0,f=1; char ch=getchar();
    	while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    	while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    	return x * f;
    }
    const int N = 1e5+7;
    int n,m,p;
    int fac[N];
    int Pow(int x,int y) {
    	int res = 1, base = x;
    	while(y) {
    		if(y&1) res = res*base%p; base = base*base%p; y >>= 1;
    	}
    	return res;
    }
    int C(int a,int b) {
    	if(a < b) return 0;
    	return fac[a] * Pow(fac[b],p-2) % p * Pow(fac[a-b],p-2) % p;
    }
    int Lucas(int a,int b) {	// (a,b)
    	if(!b) return 1;
    	return C(a%p,b%p) * Lucas(a/p,b/p) % p;
    }
    void work() {
    	n = read(), m = read(), p = read();
    	fac[0] = 1;
    	for(int i=1;i<=p;++i) fac[i] = fac[i-1] * i % p;
    	printf("%lld
    ",Lucas(n+m,m));
    }
    signed main()
    {
    	int T = read();
    	while(T--) work();
    	return 0;
    }
    

    感谢

    感谢 NCC-79601 【学习笔记】卢卡斯定理Combatting 卢卡斯定理(十分钟带你看懂) 帮助我学会了卢卡斯定理。

    感谢您的阅读,您的点赞是对我最大的支持!

    扩展

    当且仅当 (n & m = m)(即 (m)(n) 二进制下的子集)时,(dbinom{n}{m} equiv 1 pmod{2})

    证明:
    根据 (Lucas) 定理,有:

    [dbinom{n}{m} equiv dbinom{n\%2}{m\%2}*dbinom{lfloor n/2 floor}{lfloor m/2 floor} pmod{2} ]

    (n\%2)(lfloor n/2 floor) 放在二进制下思考,可以发现是一个递归的问题。 (dbinom{0}{1}=0),其他都是 (0)
    综上,当且仅当 (n & m = m)(即 (m)(n) 二进制下的子集)时,(dbinom{n}{m} equiv 1 pmod{2})。证毕。

    PS:进一步可以扩展到 (mod p),只要转化到 (p) 进制下思考即可。

  • 相关阅读:
    202020211 20209326 《Linux内核原理与分析》第一周作业
    指针入门,以及利用指针简单的数组逆置
    函数入门
    C语言关于处理数组元素的插入、删除、排序
    flag用法之一
    css3中的transform值matrix
    HTML5CANVAS做的打砖块游戏。。。
    用curl抓取网站数据,仿造IP、防屏蔽终极强悍解决方式
    javascript中最好用的extend继承方法
    使用CSS3中Media Queries兼容不同设备
  • 原文地址:https://www.cnblogs.com/BaseAI/p/12234591.html
Copyright © 2011-2022 走看看