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

    当 p 为质数,(1 le m le n) 时,求组合数(C_{n}^{m} mod{p})

    Lucas定理

    对于质数 p, 有:

    [egin{aligned} C_{n}^{m} equiv C_{n / p}^{m / p} cdot C_{n mod{p}}^{m mod {p}} pmod{p} end{aligned} ]

    其中(n / p)(m / p) 为整除。

    证明:

    引理1:

    [egin{aligned} C_{p}^{i} equiv frac{p}{i} cdot C_{p - 1}^{i - 1} equiv 0 pmod{p} end{aligned} ]

    引理1证明:

    [egin{aligned} C_{p}^{i} = frac{p!}{i! cdot (p - i)!} = frac{p}{i} cdot frac{(p - 1)}{(i - 1)! cdot (p - i)!} end{aligned} ]

    得证。
    引理2:

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

    引理2证明:(二项式定理)

    [egin{aligned} (1 + x)^p = C_p^0 + C_p^1 cdot x + ... + C_p^p cdot x^p end{aligned} ]

    从第二项到倒数第二项都可以在模 p 意义下消掉,只剩下第一项和最后一项,得证。

    Lucas定理:
    (n = s cdot p + q, m = t cdot p + r), 则(s = left lfloor frac{m}{p} ight floor, t = left lfloor frac{m}{p} ight floor)

    [egin{aligned} (1 + x)^n = [(1 + x)^p]^s cdot (1 + x)^q equiv (1 + x^p) ^ s cdot (1 + x) ^ q equiv sum_{i = 0}^{s} (C_s^i cdot x^{ip}) cdot sum_{j = 0} ^ q (C_{q}^{j} cdot x^j) pmod{p} qquad (1) end{aligned} ]

    又因为:

    [egin{aligned} (1 + x) ^ n = (1 + x)^{sp + q} = sum_{k = 0} ^ {sp + q} C_{sp + q} ^ {k} cdot x^k qquad (2) end{aligned} ]

    因为 ((1) equiv (2) pmod{p}) , 对比其中的 (x^{tp + r})项:

    [egin{aligned} C_{sp + 1} ^ {tp + r} cdot x ^ {tp + r} equiv C_s^t cdot x^{tp} cdot C_q^ r cdot x^r pmod{p} end{aligned} ]

    [egin{aligned} C_{sp + 1} ^ {tp + r} equiv C_s^t cdot C_q^ r pmod{p} end{aligned} ]

    [egin{aligned} C_{n}^{m} equiv C_{n / p}^{m / p} cdot C_{n mod{p}}^{m mod {p}} pmod{p} end{aligned} ]

    得证。

    于是可以递归求解。

    cpp:

    lld powe(lld a, lld b, lld p) {
    	lld base = 1;
    	while(b) {
    		if(b & 1) base = (base * a) % p;
    		a = (a * a) % p; b >>= 1;
    	}
    	return base;
    }
    lld comb(lld n, lld m, lld p) {
    	if(n < m) return 0;
    	if(n == m) return 1;
    	if(m > n - n) m = n - m;
    	lld cn = 1, cm = 1;
    	for(lld i = 0; i < m; i++) {
    		cn = (cn * (n - i)) % p;
    		cm = (cm * (i + 1)) % p;
    	}
    	return (cn * powe(cm, p - 2, p)) % p;
    }
    lld lucas(lld n, lld m, lld p) {
    	lld ans = 1;
    	while(n && m && ans) {
    		ans = (ans * comb(n % p, m % p, p)) % p;
    		n /= p;
    		m /= p;
    	}
    	return ans % p;
    }
    int main() {
    	int T; scanf("%d", &T);
    	while(T--) {
    		lld n, m, p;
    		scanf("%lld%lld%lld", &n, &m, &p);
    		printf("%lld
    ", lucas(n, m, p));
    	}
    	return 0;
    }
    
  • 相关阅读:
    [redis读书笔记] 第二部分 sentinel
    [redis读书笔记] 第三部分 多机数据库的实现 复制
    单线程的REDIS为什么这么快?
    [redis读书笔记] 第二部分 单机数据库 RDB持久化
    [redis读书笔记] 第二部分 单机数据库 数据库实现
    选靓号——拼多多笔试题(贪心+暴力)
    种树——拼多多笔试题(暴搜+剪枝)
    【学习笔记】《Java编程思想》 第8~11章
    leetcode——二分
    CodeForces-1265E(期望)
  • 原文地址:https://www.cnblogs.com/mcggvc/p/12895789.html
Copyright © 2011-2022 走看看