【学习笔记】扩展卢卡斯定理 exLucas
引子
求
\]
不保证 \(p\) 是质数。
正文
对于传统的 Lucas 定理,必须要求 \(p\) 是质数才行。若 \(p\) 不一定是质数,则需要扩展 Lucas 定理
前置知识
扩展欧几里得和中国剩余定理。
算法内容
将 \(p\) 用唯一分解定理分解,即
\]
若求出了
\]
就可以用中国剩余定理合并答案了。那么此时我们要求的就是
\]
但是显然 \(m!\) 和 \((n-m)!\) 在 \(\text{mod}\ p^k\) 的意义下不一定存在逆元。
对于两个数 \(a\) 和 \(p\),存在逆元的充要条件是 \(\gcd(a,p)=1\)。
所以我们可以强行让他们互质。令 \(x,y,z\) 分别为 \(n!,m!,(n-m)!\) 中 \(p\) 因子的个数,我们可以将原式转化得到
\]
这样我们就可以求逆元了,那么问题就转化成了对于每一个数 \(n\) ,求出 \(\cfrac{n!}{p^x}\ \text{mod}\ p^k\) 即可。
将 \(n!\) 展开
\]
其中左边的括号内是 \(p\) 的所有倍数。
易知,在 \(1\) ~ \(n\) 中,有 \(\bigg\lfloor\cfrac{n}{p}\bigg\rfloor\) 个 \(p\) 的倍数。因此继续变形原式
\]
\]
然后你就发现他可以套娃了,把第三项拆成能整除之前和余数两个部分
\]
也就是说上面这个式子是有循环节的,其中第三项是循环节 \(1\) ~ \(p\) 中非 \(p\) 倍数的乘积,而第四项则是 \(p\) 以后的。
前面这个 \(p^{\lfloor\frac{n}{p}\rfloor}\) 是要除掉的,但是别忘了 $ \bigg(\bigg\lfloor\cfrac{n}{p}\bigg\rfloor\bigg)!$ 中可能也有 \(p\) 因子。因此我们定义 \(f(n)=\cfrac{n}{p^x}\),得到
\]
且
\]
这样就可以 \(O(n\log p)\) 递推了。
回到最开始的式子
\]
此时 \(f(m)\) 一定和 \(p^k\) 互质,我们可以用扩展欧几里得求逆元来得到答案了。
现在我完全明白了!
但是还剩一个 \(p^{x-y-z}\) 没算。比如,我们要算出现在 \(f(n)\) 的 \(x\)。设 \(g(n)=x\),再看这个式子
\]
我们要求的部分就是 \(p^{\lfloor\frac{n}{p}\rfloor}\) 且乘上 \(\bigg(\bigg\lfloor\cfrac{n}{p}\bigg\rfloor\bigg)!\) 中的 \(p\) 因子。
因此我们得到递推式
\]
且
\]
所以最后的结论就是
\]
然后用中国剩余定理合并答案就可以得到结果了!
代码
#include <bits/stdc++.h>
#define int long long
typedef long long ll;
const int maxn=1e3+10;
using namespace std;
inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
}
inline int qpow(int x,int b,int p){
int ans=1,base=x;
while(b){
if(b&1)ans=ans*base%p;
base=base*base%p;
b>>=1;
}
return ans;
}
void exgcd(int a,int b,int &x,int &y){
if(!b)return x=1,y=0,void();
exgcd(b,a%b,x,y);
int z=x;x=y;y=z-a/b*y;
}
inline int inv(int a,int p){
int x=0,y=0;
exgcd(a,p,x,y);
return (x+p)%p;
}
int F(int n,int p,int P){
if(!n)return 1;
int rou=1,rem=1;//rou表示循环节中的,rem表示余数部分的
for(int i=1;i<=P;i++)
if(i%p)rou=rou*i%P;
rou=qpow(rou,n/P,P);
for(int i=P*(n/P);i<=n;i++)
if(i%p)rem=rem*(i%P)%P;
return F(n/p,p,P)*rou%P*rem%P;
}
int G(int n,int p){
if(n<p)return 0;
return (n/p)+G(n/p,p);
}
inline int C(int n,int m,int p,int P){
int x=F(n,p,P),y=inv(F(m,p,P),P),z=inv(F(n-m,p,P),P);
int Pow=qpow(p,G(n,p)-G(m,p)-G(n-m,p),P);
return x*y%P*z%P*Pow%P;
}
int tot;
int A[maxn],B[maxn];
inline void Init(int n,int m,int x){
int M=sqrt(x);
for(int i=2;i<=M;i++){
if(x%i==0){
int P=1;
while(x%i==0){
P*=i;x/=i;
}
A[++tot]=P;B[tot]=C(n,m,i,P);//算出每一个p^k意义下的答案
}
}
if(x!=1){
A[++tot]=x;B[tot]=C(n,m,x,x);
}
}
inline int exLucas(int n,int m,int p){
Init(n,m,p);
int ans=0;
for(int i=1;i<=tot;i++){
int u=p/A[i],v=inv(u,A[i]);//普通的CRT合并答案
ans=(ans+B[i]*u%p*v%p)%p;
}
return ans;
}
signed main(){
int n=read(),m=read(),p=read();
printf("%lld\n",exLucas(n,m,p));
return 0;
}
例题:礼物
一年一度的圣诞节快要来到了。每年的圣诞节小 E 都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小 E 心目中的重要性不同,在小 E 心中分量越重的人,收到的礼物会越多。
小 E 从商店中购买了 \(n\) 件礼物,打算送给 \(m\) 个人,其中送给第 \(i\) 个人礼物数量为 \(w_i\)。请你帮忙计算出送礼物的方案数(两个方案被认为是不同的,当且仅当存在某个人在这两种方案中收到的礼物不同)。由于方案数可能会很大,你只需要输出模 \(P\) 后的结果。\(P\) 不保证是质数。若无法满足条件,输出
Impossible
。
怎么这么多屑题叫礼物啊(恼)
显然答案是 \(\prod\limits_{i=1}^mC_{n-\sum_{j=1}^{i-1}w_j}^{w_i}\pmod P\),然后用扩展卢卡斯求解就可以了。至于无解情况,只要看剩余的礼物数是否为负即可。
【学习笔记】扩展卢卡斯定理 exLucas的更多相关文章
- [学习笔记]扩展LUCAS定理
可以先做这个题[SDOI2010]古代猪文 此算法和LUCAS定理没有半毛钱关系. [模板]扩展卢卡斯 不保证P是质数. $C_n^m=\frac{n!}{m!(n-m)!}$ 麻烦的是分母. 如果互 ...
- 扩展卢卡斯定理(Exlucas)
题目链接 戳我 前置知识 中国剩余定理(crt)或扩展中国剩余定理(excrt) 乘法逆元 组合数的基本运用 扩展欧几里得(exgcd) 说实话Lucas真的和这个没有什么太大的关系,但是Lucas还 ...
- 【知识总结】扩展卢卡斯定理(exLucas)
扩展卢卡斯定理用于求如下式子(其中\(p\)不一定是质数): \[C_n^m\ mod\ p\] 我们将这个问题由总体到局部地分为三个层次解决. 层次一:原问题 首先对\(p\)进行质因数分解: \[ ...
- bzoj2142 礼物——扩展卢卡斯定理
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 前几天学了扩展卢卡斯定理,今天来磕模板! 这道题式子挺好推的(连我都自己推出来了) , ...
- [笔记] 扩展Lucas定理
[笔记] 扩展\(Lucas\)定理 \(Lucas\)定理:\(\binom{n}{m} \equiv \binom{n/P}{m/P} \binom{n \% P}{m \% P}\pmod{P} ...
- 卢卡斯定理&扩展卢卡斯定理
卢卡斯定理 求\(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的题解 ...
- 【学习笔记】Polya定理
笔者经多番周折终于看懂了\(\text{Burnside}\)定理和\(\text{Polya}\)定理,特来写一篇学习笔记来记录一下. 群定义 定义:群\((G,·)\)是一个集合与一个运算·所定义 ...
- [Android学习笔记]扩展application
扩展Application对象 每一个应用程序启动之后,都会分配一个linux用户,并且运行在一个独立的进程中.默认情况下,一个应用程序只会运行在一个进程中(可以通过配置android:process ...
随机推荐
- Linux:文件和用目录权限基础
首先,用ls -i 查看文件的信息: 红框框起来的部分:-rw-r--r-- 一共是10位,第一位表示文件类型,-表示文件,d表示文件夹/目录:后面9位则表示权限 其中前三位是该文件/目录所属者的权限 ...
- Jack Straws(POJ 1127)
原题如下: Jack Straws Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 5555 Accepted: 2536 ...
- Oracle命令类别
Oracle命令类别: 数据操纵语言:DML: select; insert; delete; update; merge. 数据定义语言:DDL: create; alter; drop; trun ...
- C语言02
C语言02 1.2 C语言与C程序 1.计算语言 语言发展 机器语言:机器语言是机器能直接识别的程序语言或指令代码,勿需经过翻译,每一操作码在计算机内部都有相应的电路来完成它,或指不经翻译即可为机器直 ...
- 【征文活动】为自己发“声” —— 声网RTC征文大赛在园子里征稿
2020年8月20日,声网Agora入驻园子的新楼盘--博客园品牌专区.9月,我们与声网Agora再度合作,「为自己发"声"- RTC 征文大赛」在园子里征稿. RTC(Real- ...
- 华为云推UGO:一手抓结构迁移,一手抓SQL转换
摘要:UGO,一款专注于异构数据库对象迁移和应用迁移的专业化工具. 近日,华为云推出数据库和应用迁移 UGO,这是一款专注于异构数据库对象迁移和应用迁移的专业化工具,通过预迁移评估.结构迁移两大核心功 ...
- Shell学习(三)Shell参数传递
一.传参实例 ##脚本文件内容 #执行的文件名 echo $0; #第一个参数 echo $1; #第二个参数 echo $2; #第三个参数 echo $3; ##调用语句 ./testShell. ...
- 什么是 Opcache,如何使用 Opcache
Opcode 是啥? 我们先看一下 PHP 的执行过程: PHP 初始化执行环节,启动 Zend 引擎,加载注册的扩展模块. 初始化后读取 PHP 脚本文件,Zend 引擎对 PHP 文件进行词法分析 ...
- flutter,跟着官网一步一步创建第一个flutter应用
创建第一个flutter 编辑器: vscode 一.创建flutter项目 1.启动vscode 2.按ctrl+shift+p打开命令面板 3.输入flutter 选择Flutter: New P ...
- Python-IndentationError: expected an indented block
Error: IndentationError: expected an indented block Where? Python代码执行时候报这个错误 Why? Python代码具有严格缩进规范,默 ...