[bzoj2142]礼物(扩展lucas定理+中国剩余定理)
题意:n件礼物,送给m个人,每人的礼物数确定,求方案数。
解题关键:由于模数不是质数,所以由唯一分解定理,
$\bmod = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_s}}$
然后,分别求出每个组合数模每个$p_i^{{k_i}}$的值,这里可以用扩展lucas定理求解,(以下其实就是扩展lucas定理的简略证明)
关于$C_n^m\% {p^k}$,
$C_n^m = \frac{{n!}}{{m!(n - m)!}}$,
我们以$n=19,p=3,k=2$为例,
$\begin{array}{l}
19! = 1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19\\
= (1*2*4*5*7*8*10*11*13*14*16*17*19)*36*(1*2*3*4*5*6)
\end{array}$
通过观察,我们可以将将上式分成三部分,
第一部分,3的幂,快速幂可以直接求解;
第二部分,$n!$项,可以递归求解;
第三部分,$(1*2*4*5*7*8*10*11*13*14*16*17*19)$,此项在模${3^2}$意义下是存在循环节${p^k}$的,可以暴力求出一个循环节,然后重复即可,最后一个循环节的长度一定小于${p^k}$,可以在不提升复杂度的基础上暴力。
那我们回归最初的问题,关于$\frac{{n!}}{{m!(n - m)!}}\bmod {p^k}$的求解,由于在模意义下牵扯到求逆元,而不互质是不存在逆元的,所以需将阶乘中与模数不互质的部分提取出来,而这一定是$p$的倍数。
$\frac{{n!}}{{m!(n - m)!}} = \frac{{\frac{{n!}}{{{p^{{k_1}}}}}*{p^{{k_1}}}}}{{\frac{{m!}}{{{p^{{k_2}}}}}*{p^{{k_2}}}*\frac{{(n - m)!}}{{{p^{{k_3}}}}}*{p^{{k_3}}}}} = \frac{{\frac{{n!}}{{{p^{{k_1}}}}}}}{{\frac{{m!}}{{{p^{{k_2}}}}}*\frac{{(n - m)!}}{{{p^{{k_3}}}}}}}*{p^{{k_1} - {k_2} - {k_3}}}\bmod {p^k}$,
而$\frac{{n!}}{{{p^{{k_1}}}}},\frac{{m!}}{{{p^{{k_2}}}}},\frac{{(n - m)!}}{{{p^{{k_3}}}}}$是与${p^k}$互质的,可以求逆元。
所以,我们只需求出每个阶乘的第二部分和第三部分,关于$p$的幂,直接将三个阶乘的结果求出即可。
这种方法可以扩展到任意阶乘模非质数的情况。
最后用中国剩余定理组合一下。
注意最后不同质因数之间是互质的,所以直接crt即可,不需扩展crt。
最终的解为$C_n^{n - w[1]}C_{n - w[1]}^{w[2]}C_{n - w[1] - w[2]}^{w[3]}......$
法一:组合数求解。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
typedef long long ll;
using namespace std;
ll mod,n,m,w[],ans,x,y,module[],piset[],r[],num; ll mod_pow(ll x,ll n,ll p){
ll res=;
while(n){
if(n&) res=res*x%p;
x=x*x%p;
n>>=;
}
return res;
} ll extgcd(ll a,ll b,ll &x,ll &y){
ll d=a;
if(b) d=extgcd(b,a%b,y,x),y-=a/b*x;
else x=,y=;
return d;
} ll inv(ll t,ll mod){ extgcd(t,mod,x,y);return (x+mod)%mod;} ll multi(ll n,ll pi,ll pk){//求非互质的部分
if (!n) return ;
ll ans=;
for (ll i=;i<=pk;i++) if(i%pi) ans=ans*i%pk;
ans=mod_pow(ans,n/pk,pk);
for (ll i=;i<=n%pk;i++) if(i%pi) ans=ans*i%pk;
return ans*multi(n/pi,pi,pk)%pk;
} ll exlucas(ll n,ll m,ll pi,ll pk){//组合数 c(n,m)mod pk=pi^k
if(m>n) return ;
ll a=multi(n,pi,pk),b=multi(m,pi,pk),c=multi(n-m,pi,pk);
ll k=;
for(ll i=n;i;i/=pi) k+=i/pi;
for(ll i=m;i;i/=pi) k-=i/pi;
for(ll i=n-m;i;i/=pi) k-=i/pi;
return a*inv(b,pk)%pk*inv(c,pk)%pk*mod_pow(pi,k,pk)%pk;//组合数求解完毕
} ll crt(int n,ll *r,ll *m){
ll M=,ret=;
for(int i=;i<n;i++) M*=m[i];
for(int i=;i<n;i++){
ll w=M/m[i];
ret+=w*inv(w,m[i])*r[i];
ret%=M;
}
return (ret+M)%M;
} ll fz(ll n,ll *m,ll *piset){//分解质因子
ll num=;
for (ll i=;i*i<=n;i++){
if(n%i==){
ll pk=;
while(n%i==) pk*=i,n/=i;
m[num]=pk;
piset[num]=i;
num++;
}
}
if(n>) m[num]=n,piset[num]=n,num++;
return num;
} ll excomb(ll n,ll m){
for(int i=;i<num;i++){
r[i]=exlucas(n,m,piset[i],module[i]);
}
return crt(num,r,module);
} int main(){
scanf("%lld",&mod);
scanf("%lld%lld",&n,&m);
ll sum=;
for(int i=;i<=m;i++) scanf("%lld",&w[i]),sum+=w[i];
if(n<sum){ puts("Impossible");return ;}//puts会自动换行
num=fz(mod,module,piset);
ans=;
for(int i=;i<=m;i++){
n-=w[i-];
ll a1=excomb(n,w[i]);
ans=ans*a1%mod;
}
printf("%lld\n",ans);
return ;
}
法二:多项式系数求解。
最终解为:
$\left( {\begin{array}{*{20}{c}}
n\\
{{w_1}{w_2}...{w_n}(n - sum)}
\end{array}} \right) = \frac{{n!}}{{{w_1}!{w_2}!...{w_m}!(n - sum)!}}$
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
typedef long long ll;
using namespace std;
ll mod,P,n,m,w[],ans,x,y,module[],piset[],r[],num,jc[]; ll mod_pow(ll x,ll n,ll p){
ll res=;
while(n){
if(n&) res=res*x%p;
x=x*x%p;
n>>=;
}
return res;
} ll extgcd(ll a,ll b,ll &x,ll &y){
ll d=a;
if(b) d=extgcd(b,a%b,y,x),y-=a/b*x;
else x=,y=;
return d;
} ll inv(ll t,ll mod){ extgcd(t,mod,x,y);return (x+mod)%mod;} ll multi(ll n,ll pi,ll pk){//求非互质的部分
if (!n) return ;
ll ans=;
for (ll i=;i<=pk;i++) if(i%pi) ans=ans*i%pk;
ans=mod_pow(ans,n/pk,pk);
for (ll i=;i<=n%pk;i++) if(i%pi) ans=ans*i%pk;
return ans*multi(n/pi,pi,pk)%pk;
} ll exlucas(ll n,ll pi,ll pk){
ll ans=multi(n,pi,pk);
for(int i=;i<m;i++){
jc[i]=multi(w[i+],pi,pk);
ans=ans*inv(jc[i],pk)%pk;
}
ll k=;
for(ll i=n;i;i/=pi) k+=i/pi;
for(int i=;i<=m;i++) for(ll j=w[i];j;j/=pi) k-=j/pi;
return ans*mod_pow(pi,k,pk)%pk;
} ll crt(int n,ll *r,ll *m){
ll M=,ret=;
for(int i=;i<n;i++) M*=m[i];
for(int i=;i<n;i++){
ll w=M/m[i];
ret+=w*inv(w,m[i])*r[i];
ret%=M;
}
return (ret+M)%M;
} ll fz(ll n,ll *m,ll *piset){//分解质因子
ll num=;
for (ll i=;i*i<=n;i++){
if(n%i==){
ll pk=;
while(n%i==) pk*=i,n/=i;
m[num]=pk;
piset[num]=i;
num++;
}
}
if(n>) m[num]=n,piset[num]=n,num++;
return num;
} int main(){
scanf("%lld",&mod);
scanf("%lld%lld",&n,&m);
ll sum=;
for(int i=;i<=m;i++) scanf("%lld",&w[i]),sum+=w[i];
if(n<sum){ puts("Impossible");return ;}//puts会自动换行
if (sum<n) w[++m]=n-sum;
num=fz(mod,module,piset);
for(int i=;i<num;i++) r[i]=exlucas(n,piset[i],module[i]);
printf("%lld\n",crt(num,r,module));
return ;
}
[bzoj2142]礼物(扩展lucas定理+中国剩余定理)的更多相关文章
- BZOJ - 2142 礼物 (扩展Lucas定理)
扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...
- BZOJ1951 [Sdoi2010]古代猪文 【费马小定理 + Lucas定理 + 中国剩余定理 + 逆元递推 + 扩展欧几里得】
题目 "在那山的那边海的那边有一群小肥猪.他们活泼又聪明,他们调皮又灵敏.他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心--" --选自猪王国民歌 很久很久以前,在山的那 ...
- hdu 5446(2015长春网络赛J题 Lucas定理+中国剩余定理)
题意:M=p1*p2*...pk:求C(n,m)%M,pi小于10^5,n,m,M都是小于10^18. pi为质数 M不一定是质数 所以只能用Lucas定理求k次 C(n,m)%Pi最后会得到一个同余 ...
- [BZOJ2142]礼物(扩展Lucas)
2142: 礼物 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2286 Solved: 1009[Submit][Status][Discuss] ...
- Hdu 5446 Unknown Treasure (2015 ACM/ICPC Asia Regional Changchun Online Lucas定理 + 中国剩余定理)
题目链接: Hdu 5446 Unknown Treasure 题目描述: 就是有n个苹果,要选出来m个,问有多少种选法?还有k个素数,p1,p2,p3,...pk,结果对lcm(p1,p2,p3.. ...
- BZOJ 1951: [Sdoi2010]古代猪文 [Lucas定理 中国剩余定理]
1951: [Sdoi2010]古代猪文 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 2194 Solved: 919[Submit][Status] ...
- bzoj2142 礼物——扩展卢卡斯定理
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 前几天学了扩展卢卡斯定理,今天来磕模板! 这道题式子挺好推的(连我都自己推出来了) , ...
- BZOJ2142 礼物 扩展lucas 快速幂 数论
原文链接http://www.cnblogs.com/zhouzhendong/p/8110015.html 题目传送门 - BZOJ2142 题意概括 小E购买了n件礼物,送给m个人,送给第i个人礼 ...
- 【Lucas组合数定理+中国剩余定理】Mysterious For-HDU 4373
Mysterious For-HDU 4373 题目描述 MatRush is an ACMer from ZJUT, and he always love to create some specia ...
随机推荐
- 九度OJ 1193:矩阵转置 (矩阵计算)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1673 解决:1132 题目描述: 输入一个N*N的矩阵,将其转置后输出.要求:不得使用任何数组(就地逆置). 输入: 输入的第一行包括一个 ...
- Android笔记之获取debug.keystore和release.keystore的MD5/SHA1值
获取debug.keystore的key,如下图 获取release.keystore的key 输入命令keytool -list -v -keystore <jksFilename> 例 ...
- 忘记apple id如何更新应用?
最近ytkah的app有很多更新提示,之前注册的apple id好久没登录了,突然提示说登录需要验证安全问题,哪还记得噢,最要命的是邮箱收到的加密邮件也需要验证.重新注册一个吧,这次要注意保存相关信息 ...
- oracle decode 用法
含义解释: decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下:IF 条件=值1 THEN RETURN(翻译值1)ELSIF 条件=值2 THEN ...
- Blobstore Java API overview
Blobstore API允许你的应用程序使用(serve)叫做Blobs的数据对象.这种数据对象比Datastore服务所允许的对象的尺寸大得多.Blobs能有效地为大文件比如视频.图片提供服务,允 ...
- html5 canvas做的图表插件
用highchart的时候发现它是用svg来画图的,那么用canvas来做怎么样的. 以前做AS图表插件的时候,绘制图画主要用容器的Graphics对象来绘制,而canvas的context和Grap ...
- iOS9 - 采用3D Touch
iPhone 6s/6s Plus提供了触摸屏的另一个维度的操作手势-3D Touch,通常有下面两种应用场景: 在主屏幕上重按APP图标可以提供进入APP特定功能的快捷菜单 在APP内部,可以通过重 ...
- Python decorator @property
@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性 下面的链接很好的阐述了@property的概念和应用 http: ...
- ansible普通用户su切换问题
在现网应用中,安全加固后的主机是不允许直接以root用户登陆的,而很多命令又需要root用户来执行,在不改造现网的情况下.希望通过一个普通用户先登陆,再su切到root执行.而且每台主机的普通用户和r ...
- 性能强劲的Tokyo Cabinet 和 Tokyo Tyrant
Tokyo Cabinet Tokyo Cabinet (简称TC)是Mikio Hirabayashi开发的一种DBM的开发库,其数据文件只有一个,里面存放多个<key,value>的数 ...