[学习笔记]扩展LUCAS定理
可以先做这个题[SDOI2010]古代猪文
此算法和LUCAS定理没有半毛钱关系。

不保证P是质数。
$C_n^m=\frac{n!}{m!(n-m)!}$
麻烦的是分母。
如果互质就有逆元了。
所以可以考虑把分子分母不互质的数单独提出来处理。
然鹅P太一般,直接处理要考虑的东西太多。
我们不妨令$p=p_1^{q_1}*p_2^{q_2}*...*p_k^{q_k}$
对每一个$p_i^{q_i}$分别求解(不妨叫这个数为$pk$)(这样会容易很多)
即求ai满足:$\frac{n!}{m!(n-m)!} = a_i\space mod \space pk$
然后可以$CRT$合并
(CRT可以合并的原因是,我们可以求出满足这些同余方程的通解。发现这些解mod lcm都是同一个数x。$C_n^m$一定是这些个解之一,不管是哪一个,$mod\space lcm$即mod p都是x。我们也就求出了答案)
$\frac{n!}{m!(n-m)!} = a_i\space mod \space pk$
现在不互质的就是pi的倍数
首先我们可以把分子分母的所有$pi$质因子都提出来,然后上下次数相消。
对于$n!$中p的质因个数,就是不断除以p^i下取整。
剩下的都是和pk互质的了。存在逆元
以求$19!\space mod\space 3^2$为例
$19!=1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19$
提完质数3之后,变成:
$=(1*2*3*4*5*6)*3^2*(1*2*4*5*7*8*10*11*13*14*16*17*19)$
前面直接递归下去处理。后面的每一项,都可以%pk处理。
(不论分母还是分子位置,如果是分母位置,因为存在逆元,
10*inv =1 mod 9
1*inv = 1 mod 9
这两个inv显然是同一个inv.所以把所有项%pk没有问题
)
然后变成:
$=(1*2*3*4*5*6)*3^2*(1*2*4*5*7*8)^2*1)$
后面那个1是多出来的19
其实pk长度的循环节有n/pk个。直接算。剩下(例如这里的19),个数少于pk,直接算。
(所以,扩展LUCAS的重要适用条件是,$p_i^{q_i}$不能太大(1e5左右))
递归算出来即可。
对于分母位置的两个阶乘,算出来结果之后,再处理inv
(这里可以先乘完之后再找inv,不用一边找inv一边乘。)
(注意inv处理要用exgcd,不保证质数,不能用费马)
(CRT可以不用保存结果,Mi=p/pk 可以一次到位)
#include<bits/stdc++.h>
#define reg register int
#define il inline
#define int long long
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
ll p;
ll qm(ll x,ll y,ll pk){
x%=pk;
ll ret=;
while(y){
if(y&) ret=(ret*x)%pk;
x=(x*x)%pk;
y>>=;
}
return ret;
}
ll calc(ll n,ll pi,ll pk){//计算阶乘部分 (质因子已经提前处理这里不予考虑)
if(!n) return ;
ll res=;
for(reg i=;i<pk;++i)//每个循环节
if(i%pi) res=(res*i)%pk;
res=qm(res,n/pk,pk);
for(reg i=;i<=n%pk;++i)
if(i%pi) res=(res*i)%pk;
return res*calc(n/pi,pi,pk)%pk;
}
void exgcd(ll a,ll b,ll &x,ll &y){//exgcd
if(!b){
x=,y=;return;
}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
ll inv(ll n,ll pk){//逆元
ll x,y;exgcd(n,pk,x,y);
x=(x%pk+pk)%pk;
return x;
}
ll C(ll n,ll m,ll pi,ll pk){//计算C(n,m)mod pi^k
ll up=calc(n,pi,pk),d1=calc(m,pi,pk),d2=calc(n-m,pi,pk);
ll k=;
for(reg i=n;i;i/=pi) k+=i/pi;//处理质因子个数
for(reg i=m;i;i/=pi) k-=i/pi;
for(reg i=n-m;i;i/=pi) k-=i/pi;
return up*inv(d1,pk)%pk*inv(d2,pk)%pk*qm(pi,k,pk)%pk;
} ll CRT(ll b,ll mod){//CRT每步算出来了之后直接合并
return (b*inv(p/mod,mod)%p*(p/mod))%p;
}
ll EXLUCAS(ll n,ll m){//质因数分解+开始处理C
ll ret=;
ll tmp=p;
for(reg i=;(ll)i*i<=tmp;++i){
if(tmp%i==){
ll pi=i,pk=;
while(tmp%i==) pk*=i,tmp/=i;
(ret+=CRT(C(n,m,pi,pk),pk))%=p;
}
}
if(tmp>) (ret+=CRT(C(n,m,tmp,tmp),tmp))%=p;
return ret;
}
int main(){
ll n,m;
scanf("%lld%lld%lld",&n,&m,&p);
printf("%lld",EXLUCAS(n,m));
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2018/12/1 8:44:42
*/
这个算法的核心思路是:
1.不互质的要提出来单独处理
2.直接处理P,不互质的太多了
3.分成质因子处理,CRT合并
4.对于阶乘上下提出不互质的部分(质因子),转化成互质存在逆元的情况
5.观察剩余部分,后面可以对pk取模。
发现一部分还是阶乘,递归处理。
另一部分发现有循环节,利用循环节加速处理。
剩下的边角考虑一下。
(5本质上就是对每个数提取pi质因子,剩下的再乘起来。不过用递归和循环节加速了一下)
还有一个无聊的题:
简单的组合数学,非要考你扩展LUCAS。。。。
[学习笔记]扩展LUCAS定理的更多相关文章
- [笔记] 扩展Lucas定理
[笔记] 扩展\(Lucas\)定理 \(Lucas\)定理:\(\binom{n}{m} \equiv \binom{n/P}{m/P} \binom{n \% P}{m \% P}\pmod{P} ...
- 2015 ICL, Finals, Div. 1 Ceizenpok’s formula(组合数取模,扩展lucas定理)
J. Ceizenpok’s formula time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- 【learning】 扩展lucas定理
首先说下啥是lucas定理: $\binom n m \equiv \binom {n\%P} {m\%P} \times \binom{n/P}{m/P} \pmod P$ 借助这个定理,求$\bi ...
- BZOJ - 2142 礼物 (扩展Lucas定理)
扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...
- [bzoj2142]礼物(扩展lucas定理+中国剩余定理)
题意:n件礼物,送给m个人,每人的礼物数确定,求方案数. 解题关键:由于模数不是质数,所以由唯一分解定理, $\bmod = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_ ...
- Lucas定理和扩展Lucas定理
1.Lucas定理 首先给出式子:\(C_n^m\%p = C_{\lfloor\frac{n}{p}\rfloor}^{\lfloor\frac{m}{p}\rfloor} * C_{n\%p}^{ ...
- Ceizenpok’s formula Gym - 100633J 扩展Lucas定理 + 中国剩余定理
http://codeforces.com/gym/100633/problem/J 其实这个解法不难学的,不需要太多的数学.但是证明的话,我可能给不了严格的证明.可以看看这篇文章 http://ww ...
- 【学习笔记】Polya定理
笔者经多番周折终于看懂了\(\text{Burnside}\)定理和\(\text{Polya}\)定理,特来写一篇学习笔记来记录一下. 群定义 定义:群\((G,·)\)是一个集合与一个运算·所定义 ...
- 扩展Lucas定理
(1)Lucas定理:p为素数,则有: (2)证明: n=(ak...a2,a1,a0)p = (ak...a2,a1)p*p + a0 = [n/p]*p+a0,m=[m/p]*p+b0其次,我们 ...
随机推荐
- jquery easyui alert闪一下的问题
最近做项目使用了 jQuery EasyUI,版本是 1.4.3.x,在使用alert方法的时候如果alert后面执行页面跳转的话alert的消息只会闪一下,就跳到其他页面了 $.messager.a ...
- PHP (Yii2) 自定义业务异常类(可支持返回任意自己想要的类型数据)
public function beforeAction($action) { return parent::beforeAction($action); } public function runA ...
- 自己动手编写 Dockerfile 构建自定义的Jenkins
1.构建jenkins 镜像 vim Dockerfile FROM jenkins USER root ARG dockerGid=999 RUN echo "docker:x:${d ...
- 笨方法学python之import sys与from sys import argv的区别
这是在网上看到的一个大神的解答: sys is a module that contains “system functionality”. sys.argv is a list containing ...
- 谷歌面试官经典作品(CTCI)目录
1.1 判断一个字符串中的字符是否唯一 1.2 字符串翻转 1.3 去除字符串中重复字符 1.8 利用已知函数判断字符串是否为另一字符串的子串 2.1 从链表中移除重复结点 2.2 实现一个算法从一个 ...
- Java重写构造方法
public class TestSuper { public static void main(String[] args) { new ChildClass("alex", 1 ...
- XML与Object的范型转换
前段时间做object转换xml想了很多,所有打算整理下 做成以下的通用方法. public static bool ObjectToXml<T>(string filePath, T t ...
- c++ list_iterator demo
#include <iostream> #include <list> using namespace std; typedef list<int> Integer ...
- fiddler抓包工具的基本使用
fiddler是基于C#的HTTP抓包工具. fiddler的原理: fiddler是http代理服务器,它会抓取浏览器向服务器发送的HTTP请求,然后在将该请求发送到服务器.再获取从服务器返回的请求 ...
- 《python核心编程第二版》第2章习题
2-1 略 2-1 略 2-2 (a)打印 结果是9 (b)9 (c)一样 (d)略 (e)略 2-3 略 2-4 (a) # /usr/bin/pythonraw_input() (b) # /us ...