扩展卢卡斯定理用于求如下式子(其中\(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. pxc增量备份

    ###增备数据库,如果后续还需要再次增备,则可以再次指定--extra-lsndir,如果与上次备份指定相同的位置,该文件被覆盖# innobackupex --compress --incremen ...

  2. save density, pressure, velocity, temperature contour at one slice in xy plane-- paraview with batch Python scripts

    #### import the simple module from the paraviewfrom paraview.simple import *#### disable automatic c ...

  3. axios在实际项目中的使用介绍

    1.axios本身就封装了各种数据请求的方法 执行 GET 请求 // 为给定 ID 的 user 创建请求 axios.get('/user?ID=12345') .then(function (r ...

  4. 二、第一个ECharts图表

    <!DOCTYPE html> <head> <meta charset="utf-8"> <title>ECharts</t ...

  5. 最大公约数GCD

    基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 输入2个正整数A,B,求A与B的最大公约数. Input 2个数A,B,中间用空格隔开.(1<= A,B <= ...

  6. SQL Server memory – Internals

    https://blogs.msdn.microsoft.com/karthick_pk/2013/03/16/sql-server-memory-internals/

  7. css3 字体自适应

    css3提供了一些与当前viewpoint相关的元素,vw,vh,vim等. “viewpoint” = window size vw = 1% of viewport width 1vh = 1% ...

  8. FTP用户-禁止登录系统

    OS是Ubuntu 11.10. 1.   which nologin #/usr/sbin/nologin 2.   vim /etc/shells   #在该文件后添加/usr/sbin/nolo ...

  9. 飞思卡尔 imx6 GC0308 摄像头驱动配置调试过程

    GC0308摄像头驱动程序使用的是linux v4l2协议,通过i2c信号进行控制.GC0308摄像头.对上电时序要求非常严格,一定要依据datasheet初始化摄像头. 本驱动使用的3.10内核,所 ...

  10. POJ 2367:Genealogical tree(拓扑排序)

    Genealogical tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2738 Accepted: 1838 Spe ...