扩展卢卡斯定理用于求如下式子(其中\(p\)不一定是质数):

\[C_n^m\ mod\ p
\]

我们将这个问题由总体到局部地分为三个层次解决。

层次一:原问题

首先对\(p\)进行质因数分解:

\[p=\prod_i p_i^{k_i}
\]

显然\(p_i^{k_i}\)是两两互质的,所以如果分别求出\(C_n^m\ mod\ p_i^{k_i}\),就可以构造出若干个形如\(C_n^m=a_i\ mod\ p_i^{k_i}\)的方程,然后用中国剩余定理即可求解。

层次二:组合数模质数幂

现在的问题就转化成了求如下式子(其中\(p\)是质数):

\[C_n^m\ mod\ p^k
\]

脑补一下组合数公式\(C_n^m=\frac{n!}{m!\times (n-m)!}\),发现由于\(m!\)和\((n-m)!\)可能包含质因子\(p\),所以不能直接求他们对于\(p^k\)的逆元。此时我们可以将\(n!\)、\(m!\)、\((n-m)!\)中的质因子\(p\)全部提出来,最后再乘回去即可。即变为下式(\(k1\)为\(n!\)中质因子\(p\)的次数,\(k2\)、\(k3\)同理):

\[\frac{\frac{n!} {p^{k1}}}{\frac{m!}{p^{k2}}\times \frac{(n-m)!}{p^{k3}}}\times p^{k1-k2-k3}
\]

\(\frac{m!}{p^{k2}}\)和\(\frac{(n-m)!}{p^{k3}}\)和\(p^k\)是互质的,可以直接求逆元。

层次三:阶乘除去质因子后模质数幂

现在看看如何计算形如下式的式子。

\[\frac{n!}{p^{a}}\ mod\ p^k
\]

先考虑如何计算\(n!\ mod\ p^k\)

举个例子:\(n=22\),\(p=3\),\(k=2\)

把这个写出来:

\(22!=1\times 2\times 3\times 4\times 5\times 6\times 7\times 8\times 9\times 10 \times 11\times 12\times 13\times 14\times 15\times 16\times 17\times 18\times 19 \times 20 \times 21 \times 22\)

把其中所有\(p\)(也就是\(3\))的倍数提取出来,得到:

\(22!=3^7 \times (1\times 2\times 3\times 4\times 5\times 6\times 7)\times(1\times 2\times 4\times 5\times 7\times 8\times 10 \times 11\times 13\times 14\times 16\times 17\times 19 \times 20 \times 22 )\)

可以看出上式分为三个部分:第一个部分是\(3\)的幂,次数是小于等于\(22\)的\(3\)的倍数的个数,即\(\lfloor\frac{n}{p}\rfloor\)

第二个部分是一个阶乘\(7!\),即\(\lfloor\frac{n}{p}\rfloor!\),可以递归解决

第三个部分是\(n!\)中与\(p\)互质的部分的乘积,这一部分具有如下性质:

\(1\times 2\times 4\times 5\times 7\times 8\equiv10 \times 11\times 13\times 14\times 16\times 17\ mod\ p^k\)

在模\(3^2\)的意义下\(10\)和\(1\)同余,\(11\)和\(2\)同余……写成下式就比较显然

(\(t\)是任意正整数)

\[\prod_{i,(i,p)=1}^{p^k}i\equiv\prod_{i,(i,p)=1}^{p^k}(i+tp^k)\ mod\ p^k
\]

\(\prod_{i,(i,p)=1}^{p^k}i\)一共循环了\(\lfloor\frac{n}{p^k}\rfloor\)次,暴力求出\(\prod_{i,(i,p)=1}^{p^k}i\)然后用快速幂求它的\(\lfloor\frac{n}{p^k}\rfloor\)次幂。

最后还要乘上\(19\times 20 \times 22\)(即\(\prod_{i,(i,p)=1}^{n\ mod\ p^k}i\)),显然这一段的长度一定小于\(p^k\),暴力乘上去即可。

如上三部分的乘积就是\(n!\)。最终要求的是\(\frac{n!}{p^{a}}\ mod\ p^k\),分母全部由上述第一部分和第二部分贡献(第三部分和\(p\)互质)。而递归计算第二部分的时候已经除去了第二部分中的因子\(p\),所以最终的答案就是上述第二部分递归返回的结果和第三部分的乘积(与第一部分无关)。

结合代码方便理解:

ll fac(const ll n, const ll p, const ll pk)
{
if (!n)
return 1;
ll ans = 1;
for (int i = 1; i < pk; i++)
if (i % p)
ans = ans * i % pk;
ans = power(ans, n / pk, pk);
for (int i = 1; i <= n % pk; i++)
if (i % p)
ans = ans * i % pk;
return ans * fac(n / p, p, pk) % pk;
}

层次二:组合数模质数幂

回到这个式子

\[\frac{\frac{n!} {p^{k1}}}{\frac{m!}{p^{k2}}\times \frac{(n-m)!}{p^{k3}}}\times p^{k1-k2-k3}
\]

可以很容易地把它转换成代码(注意i要开long long):

ll C(const ll n, const ll m, const ll p, const ll pk)
{
if (n < m)
return 0;
ll f1 = fac(n, p, pk), f2 = fac(m, p, pk), f3 = fac(n - m, p, pk), cnt = 0;
for (ll i = n; i; i /= p)
cnt += i / p;
for (ll i = m; i; i /= p)
cnt -= i / p;
for (ll i = n - m; i; i /= p)
cnt -= i / p;
return f1 * inv(f2, pk) % pk * inv(f3, pk) % pk * power(p, cnt, pk) % pk;
}

层次一:原问题

完整代码(题目:洛谷4720【模板】扩展卢卡斯):

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <climits>
#include <cmath>
using namespace std;
namespace zyt
{
const int N = 1e6;
typedef long long ll;
ll n, m, p;
inline ll power(ll a, ll b, const ll p = LLONG_MAX)
{
ll ans = 1;
while (b)
{
if (b & 1)
ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}
ll fac(const ll n, const ll p, const ll pk)
{
if (!n)
return 1;
ll ans = 1;
for (int i = 1; i < pk; i++)
if (i % p)
ans = ans * i % pk;
ans = power(ans, n / pk, pk);
for (int i = 1; i <= n % pk; i++)
if (i % p)
ans = ans * i % pk;
return ans * fac(n / p, p, pk) % pk;
}
ll exgcd(const ll a, const ll b, ll &x, ll &y)
{
if (!b)
{
x = 1, y = 0;
return a;
}
ll xx, yy, g = exgcd(b, a % b, xx, yy);
x = yy;
y = xx - a / b * yy;
return g;
}
ll inv(const ll a, const ll p)
{
ll x, y;
exgcd(a, p, x, y);
return (x % p + p) % p;
}
ll C(const ll n, const ll m, const ll p, const ll pk)
{
if (n < m)
return 0;
ll f1 = fac(n, p, pk), f2 = fac(m, p, pk), f3 = fac(n - m, p, pk), cnt = 0;
for (ll i = n; i; i /= p)
cnt += i / p;
for (ll i = m; i; i /= p)
cnt -= i / p;
for (ll i = n - m; i; i /= p)
cnt -= i / p;
return f1 * inv(f2, pk) % pk * inv(f3, pk) % pk * power(p, cnt, pk) % pk;
}
ll a[N], c[N];
int cnt;
inline ll CRT()
{
ll M = 1, ans = 0;
for (int i = 0; i < cnt; i++)
M *= c[i];
for (int i = 0; i < cnt; i++)
ans = (ans + a[i] * (M / c[i]) % M * inv(M / c[i], c[i]) % M) % M;
return ans;
}
ll exlucas(const ll n, const ll m, ll p)
{
ll tmp = sqrt(p);
for (int i = 2; p > 1 && i <= tmp; i++)
{
ll tmp = 1;
while (p % i == 0)
p /= i, tmp *= i;
if (tmp > 1)
a[cnt] = C(n, m, i, tmp), c[cnt++] = tmp;
}
if (p > 1)
a[cnt] = C(n, m, p, p), c[cnt++] = p;
return CRT();
}
int work()
{
ios::sync_with_stdio(false);
cin >> n >> m >> p;
cout << exlucas(n, m, p);
return 0;
}
}
int main()
{
return zyt::work();
}

【知识总结】扩展卢卡斯定理(exLucas)的更多相关文章

  1. 【学习笔记】扩展卢卡斯定理 exLucas

    引子 求 \[C_n^m\ \text{mod}\ p \] 不保证 \(p\) 是质数. 正文 对于传统的 Lucas 定理,必须要求 \(p\) 是质数才行.若 \(p\) 不一定是质数,则需要扩 ...

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

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

  3. bzoj2142 礼物——扩展卢卡斯定理

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 前几天学了扩展卢卡斯定理,今天来磕模板! 这道题式子挺好推的(连我都自己推出来了) , ...

  4. 卢卡斯定理&扩展卢卡斯定理

    卢卡斯定理 求\(C_m^n~mod~p\) 设\(m={a_0}^{p_0}+{a_1}^{p_1}+\cdots+{a_k}^{p_k},n={b_0}^{p_0}+{b_1}^{p_1}+\cd ...

  5. LG4720 【模板】扩展卢卡斯定理

    扩展卢卡斯定理 求 \(C_n^m \bmod{p}\),其中 \(C\) 为组合数. \(1≤m≤n≤10^{18},2≤p≤1000000\) ,不保证 \(p\) 是质数. Fading的题解 ...

  6. 洛谷 P4720 【模板】扩展 / 卢卡斯 模板题

    扩展卢卡斯定理 : https://www.luogu.org/problemnew/show/P4720 卢卡斯定理:https://www.luogu.org/problemnew/show/P3 ...

  7. CRT中国剩余定理 & Lucas卢卡斯定理

    数论_CRT(中国剩余定理)& Lucas (卢卡斯定理) 前言 又是一脸懵逼的一天. 正文 按照道理来说,我们应该先做一个介绍. 中国剩余定理 中国剩余定理,Chinese Remainde ...

  8. P4720【模板】扩展卢卡斯,P2183 礼物

    扩展卢卡斯定理 最近光做模板了 想了解卢卡斯定理的去这里,那题也有我的题解 然而这题和卢卡斯定理并没有太大关系(雾 但是,首先要会的是中国剩余定理和exgcd 卢卡斯定理用于求\(n,m\)大,但模数 ...

  9. [学习笔记]扩展LUCAS定理

    可以先做这个题[SDOI2010]古代猪文 此算法和LUCAS定理没有半毛钱关系. [模板]扩展卢卡斯 不保证P是质数. $C_n^m=\frac{n!}{m!(n-m)!}$ 麻烦的是分母. 如果互 ...

随机推荐

  1. buf.writeUInt16BE()

    buf.writeUInt16BE(value, offset[, noAssert]) buf.writeUInt16LE(value, offset[, noAssert]) value {Num ...

  2. mongodb local数据库的空间初始化好大啊!

    新建立了一个replicat set,登录到primary里,show dbs一看吓一跳 local数据库竟然占用了80多G的空间 [root@wxlab31 bin]# ./mongo --host ...

  3. 最小生成树 C - Building a Space Station

    You are a member of the space station engineering team, and are assigned a task in the construction ...

  4. Filter过滤器机制

    tomcat内部过滤器采用了责任链的设计模式, Tomcat的过滤器主要由Filter.FilterChain组成,FilterChain包含一个Filter数组.当Wrapper执行FilterCh ...

  5. 淘宝手机rem的如何使用

    1.主要介绍几个移动端常用的单位rem.vw.vh,配合传统的px.百分比.<viewport>标签,兼容适配移动端的各种分辨率的手机端. rm : 这个单位是以父元素为标准来进行计算 , ...

  6. oracle 12c 初步操作

    查看是否为cdb SQL> select name,cdb,open_mode,con_id from v$database; NAME CDB OPEN_MODE CON_ID ------- ...

  7. mysql模糊查询语句

    select * from tbl_actor where first_char like 'p%' order by first_char;

  8. gogs: 如何恢复repository

    当某天gogs的数据库突然崩溃,配置数据全部消失后,要如何将之前git的repository重新加入到gogs中呢?(别问了,那个倒霉的人就是我) step 1, 2, 3, go... 1. 进入g ...

  9. 【Python】Python 标准库 urllib2 的使用细节

    转自:http://zhuoqiang.me/python-urllib2-usage.html http://www.cnblogs.com/txw1958/archive/2012/03/12/2 ...

  10. plsql developer 64位版本

    plsql developer 64位版本 http://www.3322.cc/soft/15748.html