扩展卢卡斯定理用于求如下式子(其中\(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. PAT 1079. 延迟的回文数

    PAT 1079. 延迟的回文数 给定一个 k+1 位的正整数 N,写成 ak...a1a0 的形式,其中对所有 i 有 0 <= ai < 10 且 ak > 0.N 被称为一个回 ...

  2. 【Codeforces 493C】Vasya and Basketball

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 枚举三分线(离散后)的位置 然后根据预处理的前缀和,快速算出两个队伍的分数. [代码] #include <bits/stdc++.h& ...

  3. 定时任务-----Springboot中使用Scheduled做定时任务----http://www.cnblogs.com/lirenqing/p/6596557.html

    Springboot中使用Scheduled做定时任务---http://www.cnblogs.com/lirenqing/p/6596557.html 已经验证的方案: pom文件加入依赖 < ...

  4. MaxScale初探

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://mrcto.blog.51cto.com/1923168/1437287 内容预览 ...

  5. 初识iBatis

    在JAVA EE应用程序中,持久层框架常用的有:Hibernate和IBATIS(或MyBatis),Hibernate是全自动的,IBatis是半自动的. IBatis的主要的作用是把SQL语句从我 ...

  6. [bzoj2038][2009国家集训队]小Z的袜子(hose)_莫队

    小Z的袜子 hose 2009-国家集训队 bzoj-2038 题目大意:给定一个n个袜子的序列,每个袜子有一个颜色.m次询问:每次询问一段区间中每种颜色袜子个数的平方和. 注释:$1\le n,m\ ...

  7. jconsole远程连接 jmx配置注意事项

    由于在测试程序时需要收集程序运行时的内存,CPU等消耗情况.选择了jconsole这个jdk自带工具来观察.为了不影响程序运行状态,用远程连接的方式来具体观察. 首先,程序是放在ubutun系统服务器 ...

  8. Maven奇怪的问题,当找不到Maven输出的提示错误时可以试下这个方法

    Maven有时会输出一些奇怪的错误,尤其是用Eclipse自动下载的包,然后根据提示的错误在网上找不到时,可以试下直接删除.m2文件夹,即本地仓库.然后再重新在控制台下执行打包命令来下载包.

  9. java NPE就是空指针异常,null pointer exception

    java NPE就是空指针异常,null pointer exception

  10. Oracle基础(四)pl/sql

    PL/SQL也是一种程序语言,叫做过程化SQL语言(Procedural Language/SQL). PL/SQL是Oracle数据库对SQL语句的扩展.在普通SQL语句的使用上添加了编程语言的特点 ...