【知识总结】扩展卢卡斯定理(exLucas)
扩展卢卡斯定理用于求如下式子(其中\(p\)不一定是质数):
\]
我们将这个问题由总体到局部地分为三个层次解决。
层次一:原问题
首先对\(p\)进行质因数分解:
\]
显然\(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=\frac{n!}{m!\times (n-m)!}\),发现由于\(m!\)和\((n-m)!\)可能包含质因子\(p\),所以不能直接求他们对于\(p^k\)的逆元。此时我们可以将\(n!\)、\(m!\)、\((n-m)!\)中的质因子\(p\)全部提出来,最后再乘回去即可。即变为下式(\(k1\)为\(n!\)中质因子\(p\)的次数,\(k2\)、\(k3\)同理):
\]
\(\frac{m!}{p^{k2}}\)和\(\frac{(n-m)!}{p^{k3}}\)和\(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\)一共循环了\(\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;
}
层次二:组合数模质数幂
回到这个式子
\]
可以很容易地把它转换成代码(注意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)的更多相关文章
- 【学习笔记】扩展卢卡斯定理 exLucas
		引子 求 \[C_n^m\ \text{mod}\ p \] 不保证 \(p\) 是质数. 正文 对于传统的 Lucas 定理,必须要求 \(p\) 是质数才行.若 \(p\) 不一定是质数,则需要扩 ... 
- 扩展卢卡斯定理(Exlucas)
		题目链接 戳我 前置知识 中国剩余定理(crt)或扩展中国剩余定理(excrt) 乘法逆元 组合数的基本运用 扩展欧几里得(exgcd) 说实话Lucas真的和这个没有什么太大的关系,但是Lucas还 ... 
- bzoj2142 礼物——扩展卢卡斯定理
		题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 前几天学了扩展卢卡斯定理,今天来磕模板! 这道题式子挺好推的(连我都自己推出来了) , ... 
- 卢卡斯定理&扩展卢卡斯定理
		卢卡斯定理 求\(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 ... 
- LG4720 【模板】扩展卢卡斯定理
		扩展卢卡斯定理 求 \(C_n^m \bmod{p}\),其中 \(C\) 为组合数. \(1≤m≤n≤10^{18},2≤p≤1000000\) ,不保证 \(p\) 是质数. Fading的题解 ... 
- 洛谷 P4720 【模板】扩展 / 卢卡斯  模板题
		扩展卢卡斯定理 : https://www.luogu.org/problemnew/show/P4720 卢卡斯定理:https://www.luogu.org/problemnew/show/P3 ... 
- CRT中国剩余定理 & Lucas卢卡斯定理
		数论_CRT(中国剩余定理)& Lucas (卢卡斯定理) 前言 又是一脸懵逼的一天. 正文 按照道理来说,我们应该先做一个介绍. 中国剩余定理 中国剩余定理,Chinese Remainde ... 
- P4720【模板】扩展卢卡斯,P2183 礼物
		扩展卢卡斯定理 最近光做模板了 想了解卢卡斯定理的去这里,那题也有我的题解 然而这题和卢卡斯定理并没有太大关系(雾 但是,首先要会的是中国剩余定理和exgcd 卢卡斯定理用于求\(n,m\)大,但模数 ... 
- [学习笔记]扩展LUCAS定理
		可以先做这个题[SDOI2010]古代猪文 此算法和LUCAS定理没有半毛钱关系. [模板]扩展卢卡斯 不保证P是质数. $C_n^m=\frac{n!}{m!(n-m)!}$ 麻烦的是分母. 如果互 ... 
随机推荐
- SQL学习笔记:一些高级语句
			现在以MySQL为模板.学习的方法和别的数据库写法上会有不同,但是思路基本一致. 用到的数据库表的格式: +----+--------------+-------------------------- ... 
- BZOJ 3993 Luogu P3324 [SDOI2015]星际战争 (最大流、二分答案)
			字符串终于告一段落了! 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=3993 (luogu) https://www.l ... 
- 【Codeforces 501C】Misha and Forest
			[链接] 我是链接,点我呀:) [题意] 给你一棵树 但是每个节点只告诉你出度个数 以及所有和它相连的点的异或和. 让你还原这棵树 [题解] 叶子节点的话,他所有节点的异或和就是它那唯一的一个爸爸 因 ... 
- [USACO07OCT]障碍路线Obstacle Course
			题目描述 Consider an N x N (1 <= N <= 100) square field composed of 1 by 1 tiles. Some of these ti ... 
- 用xshell5连接虚拟机,显示Could not connect to '192.168.3.128' (port 22): Connection failed.
			原因:虚拟机上没有安装或者没有启动ssh 解决: 1.安装sshserver sudo apt-get install openssh-server 2.启动ssh服务 sudo service ss ... 
- NetCore发布WebApi项目到IIS服务器中
			1.确保已在机器上安装Net Core Runtime,,下载地址: https://dotnet.microsoft.com/download 2.点击WebApi项目右键->发布,选择IIS ... 
- Jenkins+Github持续集成
			由于最近团队代码库从coding迁移到github,在CI工具的选型上尝试了travis-ci和circle-ci,最后决定自己搭建CI服务器,而我也有幸认领了这个任务的调研,因此有了这篇文章. 之前 ... 
- uva 11552 dp
			UVA 11552 - Fewest Flops 一个字符串,字符串每 k 个当作一组,组中的字符顺序能够重组.问经过重组后改字符串能够编程最少由多少块字符组成.连续的一段字符被称为块. dp[i][ ... 
- iOS-UITextView-文本输入视图的使用
			#import "ViewController.h" @interface ViewController ()<UITextViewDelegate> { UIView ... 
- LeetCode 788. Rotated Digits (旋转数字)
			X is a good number if after rotating each digit individually by 180 degrees, we get a valid number t ... 
