Lucas定理

在『组合数学基础』中,我们已经提出了\(Lucas\)定理,并给出了\(Lucas\)定理的证明,本文仅将简单回顾,并给出代码。

\(Lucas\)定理:当\(p\)为质数时,\(C_n^m\equiv C_{n\ mod\ p}^{m\ mod\ p}*C_{n/p}^{m/p}(mod\ p)\)。

在计算模域组合数时,如果模数较小,那么就可以尝试使用\(Lucas\)定理来递归求解,其时间复杂度为\(O(plog_p\min(n,m))\)。

\(Code:\)

inline long long Lucas(long long u,long long d)
{if (u<=Mod&&d<=Mod)return C(u,d) % Mod;else return Lucas(u/Mod,d/Mod) * C(u%Mod,d%Mod) % Mod;
}

本文给出了一种递归写法,由于取模操作的存在,在组合数计算函数\(C\)内也需要进行一些特判,避免一些无意义式子的计算,影响答案。

\(Code:\)

inline long long C(long long u,long long d)
{if ( u>d || u<0 || d<0 )return 0LL;//...
}

关于组合数的计算,我们也有多种方法,常用的几种如下:

\(1.\) 当\(n\),\(m\)都比较小的时候,可以根据组合数的阶乘计算公式来预处理\(n\),\(m\)范围以内的阶乘以及阶乘的逆元,然后根据询问\(O(1)\)地回答组合数。

\(2.\) 当\(n\)的范围较大,\(m\)的范围较小时,由于不适合预处理,所以我们可以直接利用有关\(m\)组合数计算式\(C_n^m=\frac{n*(n-1)*...*(n-m+1)}{m*(m-1)*...*1}\)来模拟计算,同理,分母利用逆元操作即可,时间复杂度\(O(m)\)。

Exlucas算法

与之对应的,\(Exlucas\)算法是一种用来解决与\(Lucas\)定理形式很像但更具有一般性的问题的算法。为什么不叫\(Exlucas\)定理而叫\(Exlucas\)算法呢,是因为这个算法和\(Lucas\)定理没什么关系,只是一个数论算法罢了。

对于求解模域组合数\(C_n^m\%p\),当\(p\)不一定是质数时,可以使用\(Exlucas\)算法求解。

对于这样一个问题,我们考虑对模数进行分解,设\(p=\prod_{i=1}^kp_i^{a_i}\),答案\(x=C_n^m\%p\),则可以得到\[x\equiv C_n^ m(mod\ p_i^{a_i})\]
这是一个线性同余方程组,可以使用中国剩余定理求解。

那么现在我们的问题就转换成了求解\(C_n^m\%p_i^{a_i}\)。将组合数写为阶乘的计算式,即\(C_n^m=\frac{n!}{m!(n-m)!}\)。

因为\(\frac{n!}{m!(n-m)!}\)与\(p_i^{a_i}\)不可避免的会存在公约数,所以不能直接使用\(Exeuclid\)等算法来求解逆元,那么我们就要考虑把\(\frac{n!}{m!(n-m)!}\)中有关\(p_i\)的项都提取掉,利用\(\frac{n!}{m!(n-m)!}\)是整数这一特点将分子该项的指数直接减掉分母该项的指数,再求解其余部分以及逆元,最后就能避免不互质的情况从而求解答案。

先考虑一个简单的问题,如何计算一个形如\(n!\)的数中含有多少个因子\(p\),则和阶乘分解一题类似,若设\(f(n)\)表示\(n!\)中含有因子\(p\)的个数,则有:
\[f(n)=\begin{cases}0\ (n<p)\\\lfloor \frac{n}{p} \rfloor +f(\lfloor \frac{n}{p} \rfloor)\ (n\geq p)\end{cases}\]

简单地利用\(for\)循环求解即可。

求得阶乘中因子\(p_i\)的数量后,我们的问题就变成为如何求解\(n!\)中除去所有\(p_i\)后取模\(p_i^{a_i}\)的值。对于每一项,这又需要我们分两种情况考虑:

\(1.\) 该项是除去\(p_i\)后得到的,我们将所有这样的项放在一起发现,发现除去\(p_i\)后,剩下的系数乘积也是一个阶乘,使用递归求解。
\(2.\) 该项是阶乘中原本的一项,除去情况\(1.\),我们发现阶乘中若干个连续的项在模\(p_i^{a_i}\)意义下恰好构成了循环节,其长度不超过\(p_i^{a_i}\),先暴力计算一个循环节,然后快速幂即可。对于不包括在完整循环节中的项,由于其长度小于循环节,可以暴力计算。

然后就能将求得的答案通过计算逆元求解,最后,乘上提取出的\(p_i\)剩余的若干次方即可。

考虑一个简单的例子就能加深理解:

求解\(n!\ mod\ p_i^{p_i}\),此时,\(n=19\),\(p_i=3\),\(a_i=2\)。
\[ n!=1*2*3*...*19\\=(1*2*4*5*7*8*10*11*13*14*16*17*19)*(3^6*6!) \\=(1*2*4*5*7*8)^2*19*(3^6*6!) \]

可以证明,其时间复杂度与\(O(plog_2p)\)同级。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int SIZE=300;
long long A,B,Mod,m[SIZE],r[SIZE];
inline void input(void)
{scanf("%lld%lld%lld",&A,&B,&Mod);//计算C(A,B)%Mod
}
inline long long power(long long a,long long b,long long p)
{long long res = 1;while (b){if (1&b)res = res * a % p;b >>= 1;a = a * a % p;}return res;
}
inline long long Exeuclid(long long a,long long &x,long long b,long long &y,long long c)
{if (!b){x=c/a,y=0;return a;}else{long long p = Exeuclid(b,x,a%b,y,c);long long x_ = x , y_ = y;x = y_ , y = x_ - a/b * y_;return p;}
}
inline long long inv(long long a,long long p)
{long long x_,y_;Exeuclid(a,x_,p,y_,1);return (x_+p)%p;
}
inline long long calc(long long x,long long val,long long p)
{//计算x!中除去val后模p意义下的值if (!x)return 1;long long res = 1 , last = x%p;for (long long i=1;i<=p;i++)if (i%val)res = res * i % p;res = power(res,x/p,p);for (long long i=1;i<=last;i++)if (i%val)res = res * i % p;return res * calc(x/val,val,p) % p;
}
inline long long C(long long d,long long u,long long val,long long Pow)
{long long mulup=calc(d,val,Pow) , k=0;long long muldown1=calc(u,val,Pow) , muldown2=calc(d-u,val,Pow);for (long long i=d;i;i/=val)k+=i/val;for (long long i=u;i;i/=val)k-=i/val;for (long long i=d-u;i;i/=val)k-=i/val;//计算剩余的val的指数return mulup * inv(muldown1,Pow) % Pow * inv(muldown2,Pow) % Pow * power(val,k,Pow) % Pow;
}
inline long long CRT(int cnt)
{long long m_ = Mod , M[SIZE] = {} , t[SIZE] = {} , res = 0;for (int i=1;i<=cnt;i++)M[i] = m_ / m[i];for (int i=1;i<=cnt;i++){long long y;Exeuclid(M[i],t[i],m[i],y,1);res = (res + r[i] % m_ * M[i] % m_ * t[i] % m_) % m_;}return ( res % m_ + m_ ) % m_;
}
inline long long Exlucas(void)
{int temp = Mod , cnt = 0 ;for (long long i=2;i*i<=Mod;i++){if (temp%i==0){m[++cnt] = 1;while (temp%i==0)temp /= i , m[cnt] *= i;r[cnt] = C(A,B,i,m[cnt]);}}if (temp>1) m[++cnt] = temp , r[cnt] = C(A,B,temp,m[cnt]);return CRT(cnt);
}
int main(void)
{input();printf("%lld\n",Exlucas());return 0;
}

转载于:https://www.cnblogs.com/Parsnip/p/10764776.html

『Lucas定理以及拓展Lucas』相关推荐

  1. Lucas定理和拓展Lucas定理

    用途 对于一个组合数求值的问题,一般运用阶乘来求,但有时候阶乘太大,就会超时. 而 L u c a s Lucas Lucas 定理和拓展 L u c a s Lucas Lucas 定理就是用来解决 ...

  2. lucas定理、拓展lucas定理学习小结

    lucas定理 正题 首先,这玩意就是下面这个式子: C m n % p = C m / p n / p ∗ C m % p n % p % p C_m^n\%p=C_{m/p}^{n/p}*C_{m ...

  3. lucas定理及扩展lucas定理

    还有一篇关于lucas定理的比较好的文章:关于LUCAS二项式系数同余定理的一些推广 转载原文链接:http://www.cnblogs.com/jianglangcaijin/p/3446839.h ...

  4. Lucas定理与扩展Lucas

    之前看了乘法逆元(详见除法取模与逆元),发现不能处理不互质的情况,于是去找方法,最后找到了Lucas定理... 虽然与期待中的不一样,但是还是非常有用的. (1)Lucas定理: 若p为素数,则有: ...

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

    [模板]卢卡斯定理/Lucas 定理 题目链接:luogu P3807 题目大意 求 C(n,n+m)%p 的值. p 保证是质数. 思路 Lucas 定理内容 对于非负整数 nnn,mmm,质数 p ...

  6. 专题·Lucas定理【including Lucas定理,扩展Lucas

    初见安~这里是数论专题(6)[详见数论专栏 本篇有前置知识点需要掌握,建议先了解下:费马小定理,中国剩余定理,乘法逆元 一.Lucas定理 Lucas定理用于求解的组合数取模的问题.其中p为质数. 组 ...

  7. 【bzoj1951】【古代猪文】Lucas定理+欧拉定理+孙子定理

    (上不了p站我要死了,当然是游戏原画啊) Description (题面倒是很有趣,就是太长了) 题意: 一个朝代流传的猪文文字恰好为N的k分之一,其中k是N的一个正约数(可以是1和N).不过具体是哪 ...

  8. HDU 5226 Tom and matrix(组合数学+Lucas定理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5226 题意:给一个矩阵a,a[i][j] = C(i,j)(i>=j) or 0(i < ...

  9. hdu3037 Lucas定理

    Lucas定理 Lucas(n,m,p)=c(n%p,m%p)* Lucas(n/p,m/p,p),其中lucas(n,m,p)=C(n,m)%p (这里的除号是整除) 证明--百度百科 题意:求n个 ...

最新文章

  1. Java Garbage Collection
  2. 终于有人能把Telnet跟SNMP讲明白了
  3. nagios错误: 无法打开要更新的命令文件
  4. 如何解决SAP Structure CMST_SI_ENQ的DDIC_TYPE_INCONSISTENCY问题
  5. mysql游标遍历中sql语句出现异常_MySQL中的异常处理,游标
  6. IT入门?推荐首选学习HTML5大前端
  7. yzmcms图片自适应代码_基于segment.js制作的非常有创意的分段式SVG文字动画特效...
  8. 东航期货模拟交易brockerid(期货公司的客户号)
  9. URL和Socket
  10. jwt java案例_JWT(二):使用 Java 实现 JWT
  11. [09-Dec-2012] 《少年pi的奇幻之旅》 -推荐
  12. B样条曲线与曲面相关知识点汇总
  13. ACCV 结果出来了,大家来晒一晒吧~
  14. a8处理器相当于骁龙几_iPhone 8P相当于什么水平的安卓机?发现两点劣势,其它无关紧要...
  15. 5G SA的网络架构和关键技术
  16. web前端开发零基础入门教程
  17. python对比两个数组的差异_数组对比差异
  18. 二分查找法及二分搜索树及其C++实现
  19. Linux服务器如何查看CPU占用率、内存占用、带宽占用
  20. 英语四级词汇:四级词组百词大关

热门文章

  1. 解决UnicodeEncodeError: 'ascii' codec can't encode
  2. UA MATH564 概率论 QE练习题2
  3. Windows下安装Docker图解
  4. Matlab冒号操作符图解
  5. Windows内核符号表学习总结
  6. 图解NHibernate项目框架
  7. 一些可运行的C语言数据结构代码
  8. 面试系列八 es写入数据的工作原理
  9. httpclient高频请求
  10. 回过头来看对象的四种状态强软弱虚引用的理解