• 【luogu P3807】【模板】卢卡斯定理/Lucas 定理(含 Lucas 定理证明)


    【模板】卢卡斯定理/Lucas 定理

    题目链接:luogu P3807

    题目大意

    求 C(n,n+m)%p 的值。
    p 保证是质数。

    思路

    Lucas 定理内容

    对于非负整数 (n),(m),质数 (p),有:
    (C_m^nequiv prodlimits_{i=0}^kC_{m_i}^{n^i}(mod p))
    其中 (m=m_kp^k+...+m_1p+m_0)(n=n_kp^k+...+n_1p+n_0)。(其实就是 (n,m)(p) 进制展开)

    那我们一般做题用的是递推式,也就是 (C_m^nequiv C_{leftlfloor m/p ight floor}^{leftlfloor n/p ight floor}C_{mmod p}^{nmod p}(mod p))
    (当 (n>m) 时,我们规定 (C_{m}^n=0)

    啥时候会用

    我们有时候要算组合数,可能 (C_{m}^n)(n,m) 很大,这时候一般做题就会让他取模一个数 (mod p)

    那如果 (p>m),我们可以愉快的用这个式子求:(C_{m}^n=dfrac{m!}{n!(m-n)!})
    算出 (n!)((m-n)!) 的逆元,就可以搞。

    可当 (mgeqslant p) 的时候,分母的乘法逆元可能不存在。(因为 (x)(p) 的倍数的话 (x) 就没有模 (p) 的逆元)

    那这个时候我们就可以用 Lucas 定理把这个组合数拆成几个 (m<p) 的,就可以搞了。

    证明

    证明 Lucas 定理之前,我们先证明两个式子。


    式一:

    (C_p^iequiv frac{p}{i}C_{p-1}^{i-1}equiv0(mod p),(1leqslant i<p))
    证明:
    (C_p^i=dfrac{p!}{i!(p-i)!}=dfrac{p}{i}dfrac{(p-1)!}{(i-1)!(p-1-(i-1))!}=frac{p}{i}C_{p-1}^{i-1})
    由于 (1leqslant i<p),故 (i) 会有 (p) 的逆元 (inv_i)
    (frac{p}{i}C_{p-1}^{i-1}=p imes inv_i imes C_{p-1}^{i-1})
    那这个地方都是 (p) 的倍数,那它被 (p) 取模一定是 (0),故得证。


    式二:

    根据二项式定理:
    ((1+n)^pequiv C_p^0+C_p^1x+...+C_p^{p-1}x^{p-1}+C_p^px^p(mod p))
    再根据式一 (C_p^iequiv0(mod p),(1leqslant i<p)),可以得到
    ((1+n)^pequiv C_p^0+C_p^px^pequiv 1+x^p(mod p))


    接着我们开始证明,先设 (leftlfloor m/p ight floor=q_m,leftlfloor n/p ight floor=q_n,mmod p=r_m,nmod p=r_n)
    那有 (m=q_mp+r_m,n=q_np+r_n)

    接着我们继续用二项式定理:
    ((1+x)^m=sumlimits_{i=1}^{m}C_{m}^ix^i)
    然后我们把左边给化简:
    (egin{aligned}(1+x)^m & =(1+x)^{q_mp+r_m} \ & =(1+x)^{q_mp}cdot(1+x)^{r_m} \& =[(1+x)^p]^{q_m}cdot(1+x)^{r_m}\&equiv(1+x^p)^{q_m}cdot(1+x)^{r_m}[式二]\&equivsumlimits_{i=1}^{q_m}C_{q_m}^ix^{ip}sumlimits_{i=1}^{r_m}C_{r_m}^{i}x^i(mod p)end{aligned})

    那就有:
    (sumlimits_{i=1}^{m}C_{m}^ix^iequivsumlimits_{i=1}^{q_m}C_{q_m}^ix^{ip}sumlimits_{i=1}^{r_m}C_{r_m}^{i}x^i(mod p))

    那对于任意一个数 (z),必然会有一组 (i,j) 满足 (x^z=x^{pi}x^j)
    不难看出这其实就是满足 (z=pi+j),所以当且仅当 (i=leftlfloor dfrac{z}{p} ight floor,j=zmod p)
    那也就是说左边的 (i) 取任意一个,右边都有一个新的跟它对于恒等。
    左边 (i=x),右边的就分别是 (i=leftlfloor dfrac{x}{p} ight floor,i=xmod p)

    那当 (i=x),就有:
    (egin{aligned}C_m^nx^n&=C_{q_m}^{q_n}x^{q_np}C_{r_m}^{r_n}x^{r_n}\C_m^nx^n&=C_{q_m}^{q_n}C_{r_m}^{r_n}x^{q_np+r_n}\C_m^nx^n&=C_{q_m}^{q_n}C_{r_m}^{r_n}x^nend{aligned})
    两边同乘 (inv(x^n)),就有了 (C_{m}^n=C_{q_m}^{q_n}C_{r_m}^{r_n})

    得证。

    本题

    其实逆元的话直接要用的话直接 (x^{p-2}mod p) 更好,不用像我这样线性求出每个。

    代码

    #include<cstdio>
    #define ll long long
    
    using namespace std;
    
    ll T, n, m, p;
    ll jc[100001], inv[100001];
    
    ll ksm(ll x, ll y) {
    	ll re = 1;
    	while (y) {
    		if (y & 1) re = (re * x) % p;
    		x = (x * x) % p;
    		y >>= 1;
    	}
    	return re;
    }
    
    ll C(ll x, ll y) {//暴力算组合数
    	if (x > y) return 0;
    	return ((jc[y] * inv[x]) % p * inv[y - x]) % p;
    }
    
    ll work(ll n, ll m) {//Lucas 定理
    	if (!n) return 1;
    	return (work(n / p, m / p) * C(n % p, m % p)) % p;
    }
    
    int main() {
    	scanf("%lld", &T);
    	while (T--) {
    		scanf("%lld %lld %lld", &n, &m, &p);
    		jc[0] = 1;
    		for (ll i = 1; i <= p; i++)//预处理阶乘与其逆元
    			jc[i] = (jc[i - 1] * i) % p;
    		inv[p - 1] = ksm(jc[p - 1], p - 2);
    		for (ll i = p - 2; i >= 0; i--)
    			inv[i] = (inv[i + 1] * (i + 1)) % p;
    		
    		printf("%lld
    ", work(n, n + m));
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    easyui struts后台实现tree返回json数据
    jquery扩展方法
    EasyUI tree扩展获取实心节点
    Hibernate之AbstractEntityPersister
    No CurrentSessionContext configured 异常解决
    Dubbo远程调用服务框架原理与示例
    mongodb高级操作及在Java企业级开发中的应用
    Java和MongoDB之Hello World
    Vmware 虚拟的Linux系统如何与宿主主机共享上网
    VM VirtualBox 上安装 CentOs6.4(详细)
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P3807.html
Copyright © 2020-2023  润新知