\(EXLucas\) 扩展卢卡斯定理


·题意

试求:

\[C^{m}_n \mod P \ \ \ \ \ \ \ \ \ \ \ ( P \in N ^* )
\]

注意, \(P\) 非质数( :- ) )。


·转化

可以给他进行质因数分解,成为:

\[P = \prod_{ i = 1 } ^ k p _ i ^ { { \alpha } _ i }
\]
\[\begin{cases}
x \equiv C^{m}_n ( \mod p_1^{ { \alpha }_1 } ) \\

\dots \\

x \equiv C^{m}_n ( \mod p _ i ^ { { \alpha } _ i } )

\end{cases}\]

然后因为这些后面的模数全都是互质的,所以可以用 \(CRT\) 解决他。

直接拿出随便一个式子,

得到的是

\[C_n^m \mod p _ i ^ { { \alpha } _ i }
\]

展开得:

\[\frac{n!}{m! \times (n-m)! } \mod p _ i ^ { { \alpha } _ i }
\]

但是不能把分母部分直接转逆元,因为你怎么知道 $ gcd( \beta! , p _ i ^ { { \alpha } _ i } ) $

所以你可以定义一个 $ f ( x ) 和 g( x ) $

\(f(x):\) 表示 \(x!\) 中除去所有 \(p\) 剩余的值

\(g(x):\) 表示 \(x!\) 中可以除几个 \(p\)

所以式子变成:

\[\frac{ f ( n ) }{f ( n - m ) \times f ( m ) } \times p ^ { g ( n ) - g( n - m ) - g( m ) } \mod p _ i ^ { { \alpha } _ i }
\]

现在求子任务:

\[n! \mod p _ i ^ { { \alpha } _ i }
\]

可以将能除 \(p\) 的数提出来。

得:

\[( p \times 2p \times \dots \times \left \lfloor \frac{n}{p} \right \rfloor ) \times \prod_{i=1}^{n}{ [ i \mod p \neq 0 ]i } \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \mod p _ i ^ { { \alpha } _ i }
\]

每个地方分一下,得:(写这玩意属实恶心)

\[=\left( \left\lfloor \frac{ n }{ p } \right\rfloor ! \right) \times p ^{\left\lfloor \frac{ n }{ p } \right\rfloor } \times \left(\prod_{i=1}^{p _ i ^ { { \alpha } _ i }}[i \mod p \ne 0 ]i \right)\times \left(\prod_{i=p _ i ^ { { \alpha } _ i }+1}^{ 2 \times p _ i ^ { { \alpha } _ i } }[ i \mod p \neq 0 ]\right) \dots \left(\prod_{i=(\left\lfloor \frac{ n }{ p } \right\rfloor-1)\times p _ i ^ { { \alpha } _ i } }^{\left\lfloor \frac{ n }{ p } \right\rfloor \times p _ i ^ { { \alpha } _ i }}[ i \mod p \neq 0 ]\right )\times \left(\prod_{ i = \left\lfloor \frac{ n }{ p } \right\rfloor \times p _ i ^ { { \alpha } _ i }}^{n}[i \mod p \neq 0 ]\right) \ \ \ \ \mod p _ i ^ { { \alpha } _ i }
\]

最后面的是剩余的。

注意,你的后面是有个取模的,

所以........

\[=\left( \left\lfloor \frac{ n }{ p } \right\rfloor ! \right) \times p ^{\left\lfloor \frac{ n }{ p } \right\rfloor } \times \left(\prod_{i=1}^{p _ i ^ { { \alpha } _ i }}[ i \mod p \neq 0 ]\right)^{\left\lfloor \frac{ n }{ p } \right\rfloor}\times \left(\prod_{ i = \left\lfloor \frac{ n }{ p } \right\rfloor \times p _ i ^ { { \alpha } _ i }}^{n}[i \mod p \neq 0 ]\right) \ \ \ \ \mod p _ i ^ { { \alpha } _ i }
\]

由于这是\(n!\),我们想要 \(f(n)\)

首先的,\(f(n)\) 中 肯定没有 \(p\) , 那么将有 \(p\) 的全提出来, (注意,\(\left\lfloor \frac{ n }{ p } \right\rfloor ! 可能含有\))

再浅浅的变一下形:

\[=f\left(\left\lfloor \frac{ n }{ p } \right\rfloor \right) \times p^{g(\left\lfloor \frac{ n }{ p } \right\rfloor)} \times p ^{\left\lfloor \frac{ n }{ p } \right\rfloor } \times \left(\prod_{i=1}^{p _ i ^ { { \alpha } _ i }}[ i \mod p \neq 0 ]\right)^{\left\lfloor \frac{ n }{ p } \right\rfloor}\times \left(\prod_{ i = \left\lfloor \frac{ n }{ p } \right\rfloor \times p _ i ^ { { \alpha } _ i }}^{n}[i \mod p \neq 0 ]\right) \ \ \ \ \mod p _ i ^ { { \alpha } _ i }
\]

那么 $f( n ) $ 就是将所有含 \(p\) 的式子择出去 (烦恼丢出去)

得:

\[f(n) = f\left(\left\lfloor \frac{ n }{ p } \right\rfloor \right) \times \left(\prod_{i=1}^{p _ i ^ { { \alpha } _ i }}[ i \mod p \neq 0 ]\right)^{\left\lfloor \frac{ n }{ p } \right\rfloor}\times \left(\prod_{ i = \left\lfloor \frac{ n }{ p } \right\rfloor \times p _ i ^ { { \alpha } _ i }}^{n}[i \mod p \neq 0 ]\right) \ \ \ \ \mod p _ i ^ { { \alpha } _ i }
\]

同时我们也可以得到:

\[g(n)=g \left(\left\lfloor \frac{ n }{ p } \right\rfloor \right) + \left\lfloor \frac{ n }{ p } \right\rfloor
\]

这个可以通过择出去得 \(p\) 得知。


· \(Code\)

\[exlucas の 板子
\]
点击查看代码
  1. #include<bits/stdc++.h>
  2. using namespace std ;
  3. #define int long long
  4. const int N = 1000010 ;
  5. int prime_num[ N ] , prime[ N ] , tot ;
  6. int bemod[ N ] , relive[ N ] ;
  7. inline int read( )
  8. {
  9. int x = 0 , f = 1 ;
  10. char c = getchar( ) ;
  11. while ( c > '9' || c < '0' )
  12. {
  13. if( c == '-' )
  14. {
  15. f = -f ;
  16. }
  17. c = getchar( ) ;
  18. }
  19. while ( c >= '0' && c <= '9' )
  20. {
  21. x = x * 10 + c - '0' ;
  22. c = getchar( ) ;
  23. }
  24. return x * f ;
  25. }
  26. int exgcd( int a , int b , int &x , int &y )
  27. {
  28. if ( ! b )
  29. {
  30. x = 1;
  31. y = 0;
  32. return a;
  33. }
  34. int d = exgcd( b , a % b , x , y ) ;
  35. int t = x ;
  36. x = y ;
  37. y = t - ( a / b ) * y ;
  38. return d ;
  39. }
  40. int inv( int Original , int mo )
  41. {
  42. int x , y ;
  43. exgcd( Original , mo , x , y ) ;
  44. return ( x + mo ) % mo ;
  45. }
  46. void decompose( int mod )
  47. {
  48. int tmp = mod ;
  49. for ( int i = 2 ; i <= sqrt( mod ) ; ++ i )
  50. {
  51. if( tmp % i == 0 )
  52. {
  53. prime[ ++ tot ] = i ;
  54. while( tmp % i == 0 )
  55. {
  56. tmp /= i ;
  57. prime_num[ tot ] ++ ;
  58. }
  59. }
  60. }
  61. if( tmp != 1 )
  62. {
  63. prime[ ++ tot ] = tmp ;
  64. prime_num[ tot ] ++ ;
  65. }
  66. return ;
  67. }
  68. int g( int n , int p )
  69. {
  70. if( n < p )
  71. {
  72. return 0 ;
  73. }
  74. return ( n / p ) + g( n / p , p ) ;
  75. }
  76. inline int Quick_Pow( int a , int b , int c )
  77. {
  78. int ans = 1 ;
  79. a %= c ;
  80. while ( b > 0 )
  81. {
  82. if( b & 1 ) ans = ( ans * a ) % c ;
  83. b >>= 1 ;
  84. a = ( a * a ) % c ;
  85. }
  86. return ans ;
  87. }
  88. inline int Regular_Quick_Pow( int a , int b )
  89. {
  90. int ans = 1 ;
  91. while ( b > 0 )
  92. {
  93. if( b & 1 ) ans *= a ;
  94. b >>= 1 ;
  95. a *= a ;
  96. }
  97. return ans ;
  98. }
  99. int f( int n , int p , int kala )
  100. {
  101. if( !n ) return 1 ;
  102. int res = 1 , vim = 1 ;
  103. // int kala = Regular_Quick_Pow( p , k ) ;
  104. // cout << kala << '\n' ;
  105. // if( n >= kala )
  106. // {
  107. for ( int i = 1 ; i <= kala ; ++ i )
  108. {
  109. if( i % p != 0 )
  110. {
  111. res = ( res * i ) % kala ;
  112. }
  113. }
  114. // }
  115. int up = n / kala ;
  116. res = Quick_Pow( res , up , kala ) ;
  117. for( int i = kala * ( n / kala ) ; i <= n ; ++ i )
  118. {
  119. if( i % p != 0 ) vim = ( vim * ( i % kala ) ) % kala ;
  120. }
  121. int returning = ( ( ( ( f( n / p , p , kala ) * vim ) % kala ) * res ) % kala ) ;
  122. // cout << returning << '\n' ;
  123. return returning ;
  124. }
  125. int EXCRT( int r[ ] , int mo[ ] , int n )
  126. {
  127. int m1 , m2 , r1 , r2 , p , q ;
  128. m1 = mo[ 1 ] , r1 = r[ 1 ] ;
  129. for( int i = 2 ; i <= n ; ++ i )
  130. {
  131. int x , y ;
  132. m2 = mo[ i ] , r2 = r[ i ] ;
  133. int d = exgcd( m1 , m2 , x , y ) ;
  134. //cout << d << '\n' ;
  135. if( ( r2 - r1 ) % d != 0 ) return -1 ;
  136. x = x * ( r2 - r1 ) / d ;
  137. int delta = m2 / d ;
  138. x = ( x % delta + delta ) % delta ;
  139. r1 = m1 * x + r1 ;
  140. m1 = m1 * delta ;
  141. }
  142. return ( r1 % m1 + m1 ) % m1 ;
  143. }
  144. int n , m , mod , ksum ;
  145. void get_fge( int now , int num , int i )
  146. {
  147. int kala = Regular_Quick_Pow( now , num ) ;
  148. int C1 = f( n , now , kala ) ;
  149. int C2 = f( m , now , kala ) ;
  150. int C3 = f( n - m , now , kala ) ;
  151. int G1 = g( n , now ) , G2 = g( m , now ) , G3 = g( n - m , now ) ;
  152. bemod[ i ] = ( ( ( ( ( C1 * inv( C2 , kala ) ) % kala ) * inv( C3 , kala ) % kala ) % kala ) * ( Quick_Pow( now , G1 - G2 - G3 , kala ) ) % kala ) % kala ;
  153. relive[ i ] = kala ;
  154. }
  155. signed main( )
  156. {
  157. #ifndef ONLINE_JUDGE
  158. freopen( "1.in" , "r" , stdin ) ;
  159. freopen( "1.out", "w" , stdout ) ;
  160. #endif
  161. // 扩展卢卡斯板子 -> C( n , m ) mod ( p ∈ N * )
  162. cin >> n >> m >> mod ;
  163. // decompose( mod ) ;
  164. int tmp = mod ;
  165. for ( int i = 2 ; i <= sqrt( mod ) ; ++ i )
  166. {
  167. if( tmp % i == 0 )
  168. {
  169. prime[ ++ tot ] = i ;
  170. while( tmp % i == 0 )
  171. {
  172. tmp /= i ;
  173. prime_num[ tot ] ++ ;
  174. }
  175. get_fge( prime[ tot ] , prime_num[ tot ] , tot ) ;
  176. }
  177. }
  178. if( tmp != 1 )
  179. {
  180. prime[ ++ tot ] = tmp ;
  181. prime_num[ tot ] ++ ;
  182. get_fge( prime[ tot ] , prime_num[ tot ] , tot ) ;
  183. }
  184. int ans = 0 ;
  185. for ( int i = 1 ; i <= tot ; ++ i )
  186. {
  187. int mer = mod / relive[ i ] ;
  188. int invmer = inv( mer , relive[ i ] ) ;
  189. ans = ( ans + ( mer * ( invmer * bemod[ i ] ) % mod ) % mod ) % mod ;
  190. }
  191. cout << ans ;
  192. }

结尾撒花 \(\color{pink}✿✿ヽ(°▽°)ノ✿\)

EXlucas的更多相关文章

  1. bzoj3129[Sdoi2013]方程 exlucas+容斥原理

    3129: [Sdoi2013]方程 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 582  Solved: 338[Submit][Status][ ...

  2. CRT and exlucas

    CRT 解同余方程,形如\(x \equiv c_i \ mod \ m_i\),我们对每个方程构造一个解满足: 对于第\(i\)个方程:\(x \equiv 1 \ mod \ m_i\),\(x ...

  3. Luogu2183 礼物 ExLucas、CRT

    传送门 证明自己学过exLucas 这题计算的是本质不相同的排列数量,不难得到答案是\(\frac{n!}{\prod\limits_{i=1}^m w_i! \times (n - \sum\lim ...

  4. exLucas学习笔记

    exLucas学习笔记 Tags:数学 写下抛硬币和超能粒子炮改 洛谷模板代码如下 #include<iostream> #define ll long long using namesp ...

  5. 扩展卢卡斯定理(Exlucas)

    题目链接 戳我 前置知识 中国剩余定理(crt)或扩展中国剩余定理(excrt) 乘法逆元 组合数的基本运用 扩展欧几里得(exgcd) 说实话Lucas真的和这个没有什么太大的关系,但是Lucas还 ...

  6. 【知识总结】扩展卢卡斯定理(exLucas)

    扩展卢卡斯定理用于求如下式子(其中\(p\)不一定是质数): \[C_n^m\ mod\ p\] 我们将这个问题由总体到局部地分为三个层次解决. 层次一:原问题 首先对\(p\)进行质因数分解: \[ ...

  7. Algorithm: CRT、EX-CRT & Lucas、Ex-Lucas

    中国剩余定理 中国剩余定理,Chinese Remainder Theorem,又称孙子定理,给出了一元线性同余方程组的有解判定条件,并用构造法给出了通解的具体形式. \[ \begin{aligne ...

  8. exlucas易错反思

    模板和题解 复习了一下 exlucas的模板,结果写挂四次(都没脸说自己以前写过 是该好好反思一下呢~ 错的原因如下: 第一次WA:求阶乘的时候忘了递归处理(n/p)! 第二次WA:求阶乘时把p当成循 ...

  9. 模板:exlucas

    求$C_n^m mod p$,其中p不是质数且不保证p能分解为几个不同质数的乘积(也就是不能用crt合并) #include<iostream> #include<cstdio> ...

  10. 洛谷$P$3301 $[SDOI2013]$方程 $exLucas$+容斥

    正解:$exLucas$+容斥 解题报告: 传送门! 在做了一定的容斥的题之后再看到这种题自然而然就应该想到容斥,,,? 没错这题确实就是容斥,和这题有点儿像 注意下的是这里的大于和小于条件处理方式不 ...

随机推荐

  1. 在Linux驱动中使用notifier通知链

    在Linux驱动中使用notifier通知链 背景 在驱动分析中经常看到fb_notifier_callback,现在趁有空学习一下. 介绍 linux中的观察者模式是最显然的就是"通知链& ...

  2. 3568F-Linux-RT系统测试手册

  3. 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-1-环境准备与搭建

    1.简介 Python+Playwright系列的文章还没有结束,就有好的小伙伴或者童鞋们私信公众号留言,问宏哥什么时候出Java语言的Playwright的自动化测试文章.本来想趁热打铁将Pytho ...

  4. OPC 详解 第一篇 基础概念

    一 .概述 OPC 的全称是OPC(OLE for Process Control), 用于过程控制的OLE,OLE(Object Linking and Embedding)大家都知道是对象连接与嵌 ...

  5. 使用定时器:在logs目录,每两分钟产生一个文件

    1.使用定时器:在logs目录,每两分钟产生一个文件(文件格式为:201711151323.log.201711151323.log.2017111513xx.log ...思路:定时器定时调用she ...

  6. 新知识get,vue3是如何实现在style中使用响应式变量?

    前言 vue2的时候想必大家有遇到需要在style模块中访问script模块中的响应式变量,为此我们不得不使用css变量去实现.现在vue3已经内置了这个功能啦,可以在style中使用v-bind指令 ...

  7. Math.random()方法的使用及公式

    条件1:取n-m范围的随机数(不包含m) 公式1:(int)(Math.random() * (m - n) + n); 条件2:取n-m范围的随机数(包含m) 公式2:(int)(Math.rand ...

  8. PO、VO、BO、DTO、POJO、DAO、DO

    DO: domain object持久对象就是从现实世界中抽象出来的有形或无形的业务实体. PO:persistant object持久对象最形象的理解就是一个PO就是数据库中的一条记录.好处是可以把 ...

  9. OffscreenCanvas-离屏canvas使用说明

    OffscreenCanvas 是一个实验中的新特性,主要用于提升 Canvas 2D/3D 绘图的渲染性能和使用体验.OffscreenCanvas 的 API 很简单,但是要真正掌握好如何使用. ...

  10. 2023 CSP 游记

    目录 \(\text{CSP-J}\) 游记 \(\text{CSP-S}\) 游记 \(\text{CSP-J}\) 游记 省流:\(\text{B}\) 题挂了 \(100\text{ pts}\ ...