可以先做这个题[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定理的更多相关文章

  1. [笔记] 扩展Lucas定理

    [笔记] 扩展\(Lucas\)定理 \(Lucas\)定理:\(\binom{n}{m} \equiv \binom{n/P}{m/P} \binom{n \% P}{m \% P}\pmod{P} ...

  2. 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 ...

  3. 【learning】 扩展lucas定理

    首先说下啥是lucas定理: $\binom n m \equiv \binom {n\%P} {m\%P} \times \binom{n/P}{m/P} \pmod P$ 借助这个定理,求$\bi ...

  4. BZOJ - 2142 礼物 (扩展Lucas定理)

    扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...

  5. [bzoj2142]礼物(扩展lucas定理+中国剩余定理)

    题意:n件礼物,送给m个人,每人的礼物数确定,求方案数. 解题关键:由于模数不是质数,所以由唯一分解定理, $\bmod  = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_ ...

  6. Lucas定理和扩展Lucas定理

    1.Lucas定理 首先给出式子:\(C_n^m\%p = C_{\lfloor\frac{n}{p}\rfloor}^{\lfloor\frac{m}{p}\rfloor} * C_{n\%p}^{ ...

  7. Ceizenpok’s formula Gym - 100633J 扩展Lucas定理 + 中国剩余定理

    http://codeforces.com/gym/100633/problem/J 其实这个解法不难学的,不需要太多的数学.但是证明的话,我可能给不了严格的证明.可以看看这篇文章 http://ww ...

  8. 【学习笔记】Polya定理

    笔者经多番周折终于看懂了\(\text{Burnside}\)定理和\(\text{Polya}\)定理,特来写一篇学习笔记来记录一下. 群定义 定义:群\((G,·)\)是一个集合与一个运算·所定义 ...

  9. 扩展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其次,我们 ...

随机推荐

  1. Spark-源码-TaskScheduler初始化过程, ClientActor向Master发送注册任务信息过程

    Spark版本 1.3 Spark源码 Spark.createTaskScheduler TaskScheduler初始化过程 1.// SparkContext中 /** * Create a t ...

  2. hadoop生态搭建(3节点)-06.hbase配置

    # http://archive.apache.org/dist/hbase/1.2.4/ # ==================================================== ...

  3. Leecode刷题之旅-C语言/python-26.删除数组中的重复项

    /* * @lc app=leetcode.cn id=26 lang=c * * [26] 删除排序数组中的重复项 * * https://leetcode-cn.com/problems/remo ...

  4. c/c++指针理解

    指针的概念 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址.要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占 ...

  5. Phoenix映射HBase数据表

    1. 说明 安装好phoenix后对于HBase中已经存在的数据表不会自动进行映射,所以想要再phoenix中操作HBase已有数据表就需要手动进行配置. 2. 创建HBase表 > creat ...

  6. RHCE7认证学习笔记17——KickStart安装系统

    一.自动化安装系统工具 1.Cobbler    另一个自动化安装工具: 2.Kickstart 二.使用kickstart自动化安装系统 服务器安装的软件: 1.dhcp服务   [root@lin ...

  7. OrCAD把原理图中的器件添加到原理图库

    1. 在使用OrCAD的时候,有时需要把别人的原理图里面的器件添加到自己的原理图库,方便以后使用,具体操作如下,依次选择Design Cache---元器件--Copy 2. 选中要存放的原理图库,鼠 ...

  8. Coap协议学习笔记-第一篇

    1. 物联网应用上一般使用单片机(或者其他SOC),单片机的RAM内存一般只有20KB~~128KB左右,然而一个TCP协议栈可能就20KB,所以只能用UDP,因为UDP相对小很多,然后在UDP上加了 ...

  9. Selenium PageFactory页面工厂

    使用Selenium PageFactory页面工厂的好处是: 当页面元素的位置发生变化时, 我们只需要去修改id或者xpath, 而不用去修改测试用例. import org.openqa.sele ...

  10. cpp语言程序设计教程第七章的一道编程题

    题目如下 按下列要求实现一个有关学生成绩的操作. 该类名为Student. (1)每个学生的信息包含有姓名(字符数组)和成绩(int型). (2)共有5个学生,用对象数组表示. (3)计算出5个学生中 ...