扩展卢卡斯定理

最近光做模板了

想了解卢卡斯定理的去这里,那题也有我的题解

然而这题和卢卡斯定理并没有太大关系(雾

但是,首先要会的是中国剩余定理和exgcd

卢卡斯定理用于求\(n,m\)大,但模数\(p\)是质数,且较小的情况

但这题\(p\)并不保证是质数

所以,首先可以通过唯一分解定理给\(p\)分解乘若干质数相乘的形式:\(p=\prod p_i^{r_i}\),当然\(r\)数列是分解后每个质数的指数

则我们可以对于每个\(p_i^{r_i}\),求出\(\tbinom{n}{m} \bmod {p_i^{r_i}}\),然后用crt进行合并,求出\(\tbinom{n}{m}\bmod p\)的值

所以,问题转化为:求\(\tbinom{n}{m} \bmod {p^{r}}\),\(p\)为质数(为了写起来方便 下文中所有\(p\)实际上都表示的是上文的\(p_i\),\(r\)表示\(r_i\))

又由于\(\tbinom{n}{m}=\dfrac{n!}{m!(n-m)!}\)

所以可以把\(n!\)中,所有是\(n\)的倍数的项都提出来,让它们都除以\(p\),然后就又得到了一个长度为\(\lfloor \dfrac{n}{p}\rfloor\)的从一开始的自然数数列,然后递归的求解\(\lfloor \dfrac{n}{k}\rfloor!\)

那么,对于不是\(n\)的倍数的项,可以发现,它们\(\bmod p^r\)的值以\(p^r\)为一个循环节,所以我们只要求出这个循环节内所有数相乘的积,然后做一个快速幂求它的\(\lfloor \dfrac{n}{k}\rfloor\)次方就行了

而对于\(n \bmod k\)个长度不足一个循环节的数,直接把它乘起来就行了

然后求\(n!\)中因数\(p\)出现的次数是很容易的(具体见代码),那么除法就对应减去\(p\)出现的次数

而剩下的数(也就是刚才把\(p\)除掉来求的)中不含\(p\),可以求\(\bmod p^r\)的逆元,就也能进行除法

最后记得能开long long的一定开long long

一遍过超开心

写了一晚上+一早上有什么可开心的。。。

另外这题的数据好像有些水,具体看这个帖,也不知道加强了没有

所以可以去看一下礼物这个题,lojbzoj上都有

那题知道这个算法以后思维难度几乎为0,就是求

\[\tbinom{n}{w_1}\tbinom{n-w_1}{w_2}\tbinom{n-w_1-w_2}{w_3}\dots
\]

然后这个礼物也成为了在洛谷A的第一个黑题虽然有些虚高

贴上代码

模板:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline LL read(){
LL x=0,y=1;
char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
LL n,m,p;
inline LL power(LL a,LL b,LL pr){
LL ret=1;
while(b){
if(b&1) ret=(ret*a)%pr;
b>>=1;a=(a*a)%pr;
}
return ret;
}
void exgcd(LL a,LL b,LL &x,LL &y){
if(!b) return x=1,y=0,void();
exgcd(b,a%b,x,y);
LL tmp=x;x=y;
y=tmp-a/b*y;
}
inline LL getinv(LL nn,LL mod){
LL x,y;
exgcd(nn,mod,x,y);
return (x+mod)%mod;
}
inline LL getfac(LL nn,LL pr,LL pp){//n!=x*p^y
if(!nn) return 1;
reg LL ans=1;
for(reg LL i=2;i<pr;i++)
if(i%pp) ans=ans*i%pr;
ans=power(ans,nn/pr,pr);
reg LL tmp=nn%pr;
for(reg LL i=2;i<=tmp;i++)
if(i%pp) ans=ans*i%pr;
return ans*getfac(nn/pp,pr,pp)%pr;
}
inline LL C(LL nn,LL mm,LL pp,LL pr){
LL x=getfac(nn,pr,pp),y=getfac(mm,pr,pp),z=getfac(nn-mm,pr,pp);
LL num=0;//计算因数种有几个p
for(reg LL i=nn;i;i/=pp) num+=i/pp;
for(reg LL i=mm;i;i/=pp) num-=i/pp;
for(reg LL i=nn-mm;i;i/=pp) num-=i/pp;
return x*getinv(y,pr)%pr*getinv(z,pr)%pr*power(pp,num,pr)%pr;
}
inline void crt(LL &ans,LL pr,LL ai){
ans=(ans+(getinv(p/pr,pr)*ai%p*(p/pr)%p))%p;//这里p/pr就相当于crt里的Mi
}
inline LL exlucas(){
LL ans=0,pp=p,pr,sqrt=std::sqrt(p);//pr=p^r
for(reg LL i=2;i<=sqrt;i++)if(!(pp%i)){
pr=1;
while(!(pp%i)) pp/=i,pr*=i;
crt(ans,pr,C(n,m,i,pr));
}
if(pp>1) crt(ans,pp,C(n,m,pp,pp));//还有因数
return ans;
}
int main(){
n=read();m=read();p=read();
std::printf("%lld",exlucas());
return 0;
}

礼物那题

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline LL read(){
LL x=0,y=1;
char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
LL p;
inline LL power(LL a,LL b,LL pr){
LL ret=1;
while(b){
if(b&1) ret=(ret*a)%pr;
b>>=1;a=(a*a)%pr;
}
return ret;
}
void exgcd(LL a,LL b,LL &x,LL &y){
if(!b) return x=1,y=0,void();
exgcd(b,a%b,x,y);
LL tmp=x;x=y;
y=tmp-a/b*y;
}
inline LL getinv(LL nn,LL mod){
LL x,y;
exgcd(nn,mod,x,y);
return (x+mod)%mod;
}
inline LL getfac(LL nn,LL pr,LL pp){//n!=x*p^y
if(!nn) return 1;
reg LL ans=1;
for(reg LL i=2;i<pr;i++)
if(i%pp) ans=ans*i%pr;
ans=power(ans,nn/pr,pr);
reg LL tmp=nn%pr;
for(reg LL i=2;i<=tmp;i++)
if(i%pp) ans=ans*i%pr;
return ans*getfac(nn/pp,pr,pp)%pr;
}
inline LL C(LL nn,LL mm,LL pp,LL pr){
LL x=getfac(nn,pr,pp),y=getfac(mm,pr,pp),z=getfac(nn-mm,pr,pp);
LL num=0;//计算因数种有几个p
for(reg LL i=nn;i;i/=pp) num+=i/pp;
for(reg LL i=mm;i;i/=pp) num-=i/pp;
for(reg LL i=nn-mm;i;i/=pp) num-=i/pp;
return x*getinv(y,pr)%pr*getinv(z,pr)%pr*power(pp,num,pr)%pr;
}
inline void crt(LL &ans,LL pr,LL ai){
ans=(ans+(getinv(p/pr,pr)*ai%p*(p/pr)%p))%p;//这里p/pr就相当于crt里的Mi
}
inline LL exlucas(LL n,LL m){
LL ans=0,pp=p,pr,sqrt=std::sqrt(p);//pr=p^r
for(reg LL i=2;i<=sqrt;i++)if(!(pp%i)){
pr=1;
while(!(pp%i)) pp/=i,pr*=i;
crt(ans,pr,C(n,m,i,pr));
}
if(pp>1) crt(ans,pp,C(n,m,pp,pp));//还有因数
return ans;
}
LL w[10];
int main(){
p=read();LL n=read(),m=read();
LL sum=0;
for(reg int i=1;i<=m;i++) w[i]=read(),sum+=w[i];
if(sum>n) return std::puts("Impossible"),0;
LL ans=1;
for(reg int i=1;i<=m;i++){
ans=(ans*exlucas(n,w[i]))%p;
n-=w[i];
}
std::printf("%lld",ans);
return 0;
}

P4720【模板】扩展卢卡斯,P2183 礼物的更多相关文章

  1. [洛谷P4720] [模板] 扩展卢卡斯

    题目传送门 求组合数的时候,如果模数p是质数,可以用卢卡斯定理解决. 但是卢卡斯定理仅仅适用于p是质数的情况. 当p不是质数的时候,我们就需要用扩展卢卡斯求解. 实际上,扩展卢卡斯=快速幂+快速乘+e ...

  2. 洛谷P4720 【模板】扩展卢卡斯

    P4720 [模板]扩展卢卡斯 题目背景 这是一道模板题. 题目描述 求 C(n,m)%P 其中 C 为组合数. 输入输出格式 输入格式: 一行三个整数 n,m,p ,含义由题所述. 输出格式: 一行 ...

  3. 洛谷 P4720 【模板】扩展 / 卢卡斯 模板题

    扩展卢卡斯定理 : https://www.luogu.org/problemnew/show/P4720 卢卡斯定理:https://www.luogu.org/problemnew/show/P3 ...

  4. Luogu P2183 [国家集训队]礼物 扩展卢卡斯+组合数

    好吧学长说是板子...学了之后才发现就是板子qwq 题意:求$ C_n^{w_1}*C_{n-w_1}^{w_2}*C_{n-w_1-w_2}^{w_3}*...\space mod \space P ...

  5. BZOJ2142礼物——扩展卢卡斯

    题目描述 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多.小E从商店中购买了n件礼 ...

  6. bzoj2142 礼物——扩展卢卡斯定理

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 前几天学了扩展卢卡斯定理,今天来磕模板! 这道题式子挺好推的(连我都自己推出来了) , ...

  7. 【luoguP4720】【模板】扩展卢卡斯

    快速阶乘与(扩展)卢卡斯定理 \(p\)为质数时 考虑 \(n!~mod~p\) 的性质 当\(n>>p\)时,不妨将\(n!\)中的因子\(p\)提出来 \(n!\) 可以写成 \(a* ...

  8. LG4720 【模板】扩展卢卡斯定理

    扩展卢卡斯定理 求 \(C_n^m \bmod{p}\),其中 \(C\) 为组合数. \(1≤m≤n≤10^{18},2≤p≤1000000\) ,不保证 \(p\) 是质数. Fading的题解 ...

  9. 【知识总结】扩展卢卡斯定理(exLucas)

    扩展卢卡斯定理用于求如下式子(其中\(p\)不一定是质数): \[C_n^m\ mod\ p\] 我们将这个问题由总体到局部地分为三个层次解决. 层次一:原问题 首先对\(p\)进行质因数分解: \[ ...

随机推荐

  1. Flask 入门(八)

    flask操作数据库:操作数据: 承接上文: 修改main.py中的代码如下: #encoding:utf-8 from flask_sqlalchemy import SQLAlchemy from ...

  2. 萌新带你开车上p站(一)

    本文作者:萌新 0x01前言 这一系列文章为pwnable.krToddlr’s Bottle的全部题解,其中有三道题目相对而言稍难或者说比较经典,单独成篇,其他题目的题解放在一起发出来. 0x02f ...

  3. HAproxy 基础配置

    基础配置详解 HAProxy 的配置文件haproxy.cfg由两大部分组成,分别是global和proxies部分 global:全局配置段 进程及安全配置相关的参数性能调整相关参数Debug参数 ...

  4. SpringBoot 2.x 开发案例之前后端分离鉴权

    前言 阅读本文需要一定的前后端开发基础,前后端分离已成为互联网项目开发的业界标准使用方式,通过Nginx代理+Tomcat的方式有效的进行解耦,并且前后端分离会为以后的大型分布式架构.弹性计算架构.微 ...

  5. 六、路由详细介绍之动态路由RIP(了解一下就行)

    动态路由分为距离矢量路由(RIP)和链路状态(OSPF和ISIS) 一.离矢量路由协议-RIP RIP协议现在基本上被淘汰. RIP动态路由协议工作原理,如上图: R12中有192.168.1.0和1 ...

  6. 一、Python3.8的安装

    一:什么是Python解释器 解释器(英语:Interpreter),又译为直译器,是一种电脑程序能够把高级编程语言一行一行直接转译运行. 解释器不会一次把整个程序转译出来,只像一位“中间人”,每次运 ...

  7. 用Python介绍了企业资产情况的数据爬取、分析与展示。

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:张耀杰 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自 ...

  8. Mysql大厂高频面试题

    前言 前几天有读者找到我,说想要一套全面的Mysql面试题,今天陈某特地为她写了一篇. 文章的目录如下: Mysql面试题 什么是SQL? 结构化查询语言(Structured Query Langu ...

  9. Cucumber(3)——命令以及日志

    目录 回顾 基本执行命令 关于日志的生成 回顾 在上一节中,我介绍了cucumber一些基本的语法内容,如果你还没有进行相关的了解或者环境的配置,你可以点击这里来进行了解一下 在本节中,我会对cucu ...

  10. 百度关键词搜索工具 v1.1|url采集工具 v1.1

    功能介绍:关键词搜索工具 批量关键词自动搜索采集 自动去除垃圾二级泛解析域名 可设置是否保存域名或者url 持续更新中