[笔记] 扩展Lucas定理
[笔记] 扩展\(Lucas\)定理
\(Lucas\)定理:\(\binom{n}{m} \equiv \binom{n/P}{m/P} \binom{n \% P}{m \% P}\pmod{P}\)\((P\ is \ prime)\)
Theory
那么如果\(p\)不是一个质数怎么办?
当我们需要计算\(C_n^m\mod p\),其中\(p = p_1^{q_1}\times p_2^{q_2}\times ...\times p_k^{q_k}\),我们可以求出:\(C_n^m\equiv a_i\pmod {p_i^{q_i}} (1\lt i \lt k)\)
然后对于方程组:
\(x\equiv a_i \pmod {p_i^{q_i}}(1\lt i\lt k)\)
我们可以求出满足条件的最小的\(x\),记为\(x_0\)那么我们有: \(C_n^m\equiv x_0\pmod p\)
但是,我们发现,\(p_i^{q_i}\)并不是一个素数,它是某个素数的某次方。
下面我们介绍如何计算\(C_n^m \mod p^t(t\ge2,p \ is \ prime)\)
我们知道,\(C_n^m=\frac {n!}{m!(n-m)!}\),若我们可以计算出\(m!\mod p^t\),我们就能计算出\((n-m)!\mod p^t\)以及\((n-m)!\mod p^t\).
我们不妨设\(x=n!\mod p^t,y=m!\mod p^t,z=(n-m)!\mod p^t,\)
那么答案就是
\(x\cdot inv(y,p^t)\cdot inv(z,p^t)\)那么下面问题就转化成如何计算\(n!\mod p^t\).
例如\(p=3,t=2,n=19\)
\(n!=1\times2\times3\times4\times5\times6\times7\times8\times ...\times19 \\ \ \ \ =(1\times2\times4\times5\times7\times8\times...\times16\times17\times19)\times(3\times6\times9\times12\times15\times18)\\\ \ \ =(1\times2\times4\times5\times7\times8\times...\times16\times17\times19)\times3^6\times(1\times2\times3\times4\times5\times6)\)
部分恰好是\((n/p)!\),于是递归即可。前半部分是以\(p^t\)为周期的\((1\times2\times4\times5\times7\times8)\equiv(10\times11\times13\times14\times16\times17)\pmod9\).下面是孤立的\(19\),可以知道孤立出来的长度不超过\(p^t\),于是直接计算即可。对于最后剩下的\(3^6\)这些数我们只要计算出\(n!,m!,(n-m)!\)里含有多少个\(p\)(不妨设\(x,y,z\)),那么\(x−y−z\)就是\(C_n^m\)中\(p\)的个数,直接计算就行。
Code
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
typedef long long ll;
const ll N = 1e6 + 5;
ll g_x, g_y, cnt;
ll d[N], r[N];
ll q_pow(ll a, ll b, ll p){
ll w = 1;
while(b){
if(b & 1)
w = (a * w) % p;
b >>= 1;//1
a = (a * a) % p;
}
return w % p;
}
ll exgcd(ll a, ll b){
if(b == 0){
g_x = 1;
g_y = 0;
return a;
}
ll gcd = exgcd(b, a % b);
ll t = g_x;
g_x = g_y;
g_y = t - a / b * g_y;
return gcd;
}/*exgcd求逆元 , ab + mt = 1, 前提: gcd(a, m) = 1;
用exgcd求逆元有个好处,不用让模数为素数,只要模数和这个a互质就好*/
ll inv(ll a, ll p){
exgcd(a, p);
return (g_x % p + p) % p;
}
ll fac(ll n, ll pi, ll pk){
if(!n) return 1; //2 //递归边界
ll res = 1;
for(register ll i = 2; i <= pk; ++i){
if(i % pi)//3 pk
res = (res * i) % pk;
}/*因为循环节长度最多为pk,所以只需要算一遍pk,选这些数字里面不是pi倍数的数字
(因为是倍数的,我们已经处理掉了*/
res = q_pow(res, n / pk, pk);//有n/pk个循环
for(register ll i = 2; i <= n % pk; ++i){
if(i % pi)//3 pk
res = (res * i) % pk;//剩下的暴力做
}
return (res * fac(n / pi, pi, pk)) % pk; //递归继续
}
void cal(ll n, ll m, ll pi, ll pk){
ll up = fac(n, pi, pk), d1 = fac(n - m, pi, pk), d2 = fac(m, pi, pk);
ll k = 0;
for(register ll i = n; i; i /= pi) k += i / pi;
for(register ll i = m; i; i /= pi) k -= i / pi;
for(register ll i = n - m; i; i /= pi) k -= i / pi;//这三行都是统计pi倍数的个数,后两个要减去是因为组合数的计算不就有个除嘛
r[++cnt] = q_pow(pi, k, pk) % pk * up % pk * inv(d1, pk) % pk * inv(d2, pk) % pk;
d[cnt] = pk;//CRT,r表示余数,d表示除数
}
ll mul(ll a, ll b, ll p){
ll f = 1;
if(a < 0) f = -f, a = -a;
if(b < 0) f = -f, b = -b;
ll w = 0;
while(b){
if(b & 1)
w = (w + a) % p;
b >>= 1;
a = (a + a) % p;
}
return w * f;
}//龟速乘
ll exCRT(){
for(register ll i = 2; i <= cnt; ++i){
ll C = r[1] - r[i];
ll D = exgcd(d[i], d[1]);
if(C % D) return -1;
ll k1 = mul(g_y, C / D, d[1] / D * d[i]);
ll x0 = mul(-k1 , d[1], d[1] / D * d[i] ) + r[1];
d[1] = d[1] / D * d[i], r[1] = x0;
r[1] = (r[1] % d[1] + d[1]) % d[1];
}
return r[1];//很好的exCRT
}
ll exlucas(ll n, ll m, ll p){
ll lim = sqrt(p) + 1;
ll tmp = p;
ll pk;
for(register ll i = 2; i <= lim; ++i){
if(tmp % i == 0){
pk = 1;
while(tmp % i == 0){
pk *= i;
tmp /= i;//为了得出pk
}
cal(n, m, i, pk);
}
}//唯一分解
if(tmp > 1) cal(n, m, tmp, tmp);//4 唯一分解后可能会留下一个大素数
return exCRT() % p;//5 pk
}
int main(){
ll n, m, p;
scanf("%lld %lld %lld", &n, &m, &p);
printf("%lld\n", exlucas(n, m, p));
}
Wrong
- 快速幂中的指数忘记右移
- \(fac\)递归边界忽略掉了
- 循环节计算时,是取那些不是\(pi\)倍数的,而不是不是\(pk\)倍数的
- \(exCRT\)最后模的是\(p\),不是\(pk\)!!!
爱你哟
[笔记] 扩展Lucas定理的更多相关文章
- [学习笔记]扩展LUCAS定理
可以先做这个题[SDOI2010]古代猪文 此算法和LUCAS定理没有半毛钱关系. [模板]扩展卢卡斯 不保证P是质数. $C_n^m=\frac{n!}{m!(n-m)!}$ 麻烦的是分母. 如果互 ...
- 2015 ICL, Finals, Div. 1 Ceizenpok’s formula(组合数取模,扩展lucas定理)
J. Ceizenpok’s formula time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- 【learning】 扩展lucas定理
首先说下啥是lucas定理: $\binom n m \equiv \binom {n\%P} {m\%P} \times \binom{n/P}{m/P} \pmod P$ 借助这个定理,求$\bi ...
- BZOJ - 2142 礼物 (扩展Lucas定理)
扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...
- [bzoj2142]礼物(扩展lucas定理+中国剩余定理)
题意:n件礼物,送给m个人,每人的礼物数确定,求方案数. 解题关键:由于模数不是质数,所以由唯一分解定理, $\bmod = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_ ...
- Lucas定理和扩展Lucas定理
1.Lucas定理 首先给出式子:\(C_n^m\%p = C_{\lfloor\frac{n}{p}\rfloor}^{\lfloor\frac{m}{p}\rfloor} * C_{n\%p}^{ ...
- Ceizenpok’s formula Gym - 100633J 扩展Lucas定理 + 中国剩余定理
http://codeforces.com/gym/100633/problem/J 其实这个解法不难学的,不需要太多的数学.但是证明的话,我可能给不了严格的证明.可以看看这篇文章 http://ww ...
- 扩展Lucas定理
(1)Lucas定理:p为素数,则有: (2)证明: n=(ak...a2,a1,a0)p = (ak...a2,a1)p*p + a0 = [n/p]*p+a0,m=[m/p]*p+b0其次,我们 ...
- 扩展Lucas定理 扩展Lucas板子
题意概述:多组询问,给出N,K,M,要求回答C(N,K)%M,1<=N<=10^18,1<=K<=N,2<=M<=10^6 分析: 模数不为质数只能用扩展Lucas ...
随机推荐
- Seq2Seq原理详解
一.Seq2Seq简介 seq2seq 是一个Encoder–Decoder 结构的网络,它的输入是一个序列,输出也是一个序列.Encoder 中将一个可变长度的信号序列变为固定长度的向量表达,Dec ...
- 【非原创】codeforces 1063B Labyrinth 【01bfs】
学习博客:戳这里 附本人代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 co ...
- Python源码剖析——02虚拟机
<Python源码剖析>笔记 第七章:编译结果 1.大概过程 运行一个Python程序会经历以下几个步骤: 由解释器对源文件(.py)进行编译,得到字节码(.pyc文件) 然后由虚拟机按照 ...
- C# TextBlock
TextBlock 适合长文本多行显示,Label可以看成是一个简短的单行的TextBlock,只是Label可以显示图片,TextBlock只能显示纯文本 默认的文本不会分行显示,超出窗体宽度的字符 ...
- Nuxt.js SSR Optimizing Tips
Nuxt.js SSR Optimizing Tips 性能优化 FP 首次绘制时间 FCP 首次渲染时间 FMP 首屏渲染时间 FI refs https://vueschool.io/articl ...
- how to disabled alert function in javascript
how to disabled alert function in javascript alert 阻塞主线程 default alert; // ƒ alert() { [native code] ...
- React Hooks & useCallback & useMemo
React Hooks & useCallback & useMemo https://reactjs.org/docs/hooks-reference.html#usecallbac ...
- 如何理解NGK的Layer2-侧链?
对于 NGK来说,Layer-2越来越重要,并成为共识.但是,"Layer-2" 是个不精确的标签.有些人说起 "Layer-2" 时,仅仅指的是 " ...
- 区块链项目NGK未来价值几何?
没有人可以预知NGK未来会涨到多少钱,就像比特币只有10美分时,也无法预测它会涨到现在的价格⼀样.那时候人们把CPU超频挖矿只作为⼀种爱好和娱乐.所以,人们也没有办法预知NGK未来的价格.但可以知道的 ...
- OpenCVE-开源漏洞预警平台
0x01简介 主程序主要是通过使用NVD提供的JSON数据来更新CVE数据,并在前端进行展示.然后通过邮件进行通知,目前也只支持邮件.这个开源预警平台看上去并不是很完善,因为CVE本身就具有预警滞后性 ...