题意: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]}......$

法一:组合数求解。

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cmath>
  6. #include<cstdlib>
  7. typedef long long ll;
  8. using namespace std;
  9. ll mod,n,m,w[],ans,x,y,module[],piset[],r[],num;
  10.  
  11. ll mod_pow(ll x,ll n,ll p){
  12. ll res=;
  13. while(n){
  14. if(n&) res=res*x%p;
  15. x=x*x%p;
  16. n>>=;
  17. }
  18. return res;
  19. }
  20.  
  21. ll extgcd(ll a,ll b,ll &x,ll &y){
  22. ll d=a;
  23. if(b) d=extgcd(b,a%b,y,x),y-=a/b*x;
  24. else x=,y=;
  25. return d;
  26. }
  27.  
  28. ll inv(ll t,ll mod){ extgcd(t,mod,x,y);return (x+mod)%mod;}
  29.  
  30. ll multi(ll n,ll pi,ll pk){//求非互质的部分
  31. if (!n) return ;
  32. ll ans=;
  33. for (ll i=;i<=pk;i++) if(i%pi) ans=ans*i%pk;
  34. ans=mod_pow(ans,n/pk,pk);
  35. for (ll i=;i<=n%pk;i++) if(i%pi) ans=ans*i%pk;
  36. return ans*multi(n/pi,pi,pk)%pk;
  37. }
  38.  
  39. ll exlucas(ll n,ll m,ll pi,ll pk){//组合数 c(n,m)mod pk=pi^k
  40. if(m>n) return ;
  41. ll a=multi(n,pi,pk),b=multi(m,pi,pk),c=multi(n-m,pi,pk);
  42. ll k=;
  43. for(ll i=n;i;i/=pi) k+=i/pi;
  44. for(ll i=m;i;i/=pi) k-=i/pi;
  45. for(ll i=n-m;i;i/=pi) k-=i/pi;
  46. return a*inv(b,pk)%pk*inv(c,pk)%pk*mod_pow(pi,k,pk)%pk;//组合数求解完毕
  47. }
  48.  
  49. ll crt(int n,ll *r,ll *m){
  50. ll M=,ret=;
  51. for(int i=;i<n;i++) M*=m[i];
  52. for(int i=;i<n;i++){
  53. ll w=M/m[i];
  54. ret+=w*inv(w,m[i])*r[i];
  55. ret%=M;
  56. }
  57. return (ret+M)%M;
  58. }
  59.  
  60. ll fz(ll n,ll *m,ll *piset){//分解质因子
  61. ll num=;
  62. for (ll i=;i*i<=n;i++){
  63. if(n%i==){
  64. ll pk=;
  65. while(n%i==) pk*=i,n/=i;
  66. m[num]=pk;
  67. piset[num]=i;
  68. num++;
  69. }
  70. }
  71. if(n>) m[num]=n,piset[num]=n,num++;
  72. return num;
  73. }
  74.  
  75. ll excomb(ll n,ll m){
  76. for(int i=;i<num;i++){
  77. r[i]=exlucas(n,m,piset[i],module[i]);
  78. }
  79. return crt(num,r,module);
  80. }
  81.  
  82. int main(){
  83. scanf("%lld",&mod);
  84. scanf("%lld%lld",&n,&m);
  85. ll sum=;
  86. for(int i=;i<=m;i++) scanf("%lld",&w[i]),sum+=w[i];
  87. if(n<sum){ puts("Impossible");return ;}//puts会自动换行
  88. num=fz(mod,module,piset);
  89. ans=;
  90. for(int i=;i<=m;i++){
  91. n-=w[i-];
  92. ll a1=excomb(n,w[i]);
  93. ans=ans*a1%mod;
  94. }
  95. printf("%lld\n",ans);
  96. return ;
  97. }

法二:多项式系数求解。

最终解为:

$\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)!}}$

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cmath>
  6. #include<cstdlib>
  7. typedef long long ll;
  8. using namespace std;
  9. ll mod,P,n,m,w[],ans,x,y,module[],piset[],r[],num,jc[];
  10.  
  11. ll mod_pow(ll x,ll n,ll p){
  12. ll res=;
  13. while(n){
  14. if(n&) res=res*x%p;
  15. x=x*x%p;
  16. n>>=;
  17. }
  18. return res;
  19. }
  20.  
  21. ll extgcd(ll a,ll b,ll &x,ll &y){
  22. ll d=a;
  23. if(b) d=extgcd(b,a%b,y,x),y-=a/b*x;
  24. else x=,y=;
  25. return d;
  26. }
  27.  
  28. ll inv(ll t,ll mod){ extgcd(t,mod,x,y);return (x+mod)%mod;}
  29.  
  30. ll multi(ll n,ll pi,ll pk){//求非互质的部分
  31. if (!n) return ;
  32. ll ans=;
  33. for (ll i=;i<=pk;i++) if(i%pi) ans=ans*i%pk;
  34. ans=mod_pow(ans,n/pk,pk);
  35. for (ll i=;i<=n%pk;i++) if(i%pi) ans=ans*i%pk;
  36. return ans*multi(n/pi,pi,pk)%pk;
  37. }
  38.  
  39. ll exlucas(ll n,ll pi,ll pk){
  40. ll ans=multi(n,pi,pk);
  41. for(int i=;i<m;i++){
  42. jc[i]=multi(w[i+],pi,pk);
  43. ans=ans*inv(jc[i],pk)%pk;
  44. }
  45. ll k=;
  46. for(ll i=n;i;i/=pi) k+=i/pi;
  47. for(int i=;i<=m;i++) for(ll j=w[i];j;j/=pi) k-=j/pi;
  48. return ans*mod_pow(pi,k,pk)%pk;
  49. }
  50.  
  51. ll crt(int n,ll *r,ll *m){
  52. ll M=,ret=;
  53. for(int i=;i<n;i++) M*=m[i];
  54. for(int i=;i<n;i++){
  55. ll w=M/m[i];
  56. ret+=w*inv(w,m[i])*r[i];
  57. ret%=M;
  58. }
  59. return (ret+M)%M;
  60. }
  61.  
  62. ll fz(ll n,ll *m,ll *piset){//分解质因子
  63. ll num=;
  64. for (ll i=;i*i<=n;i++){
  65. if(n%i==){
  66. ll pk=;
  67. while(n%i==) pk*=i,n/=i;
  68. m[num]=pk;
  69. piset[num]=i;
  70. num++;
  71. }
  72. }
  73. if(n>) m[num]=n,piset[num]=n,num++;
  74. return num;
  75. }
  76.  
  77. int main(){
  78. scanf("%lld",&mod);
  79. scanf("%lld%lld",&n,&m);
  80. ll sum=;
  81. for(int i=;i<=m;i++) scanf("%lld",&w[i]),sum+=w[i];
  82. if(n<sum){ puts("Impossible");return ;}//puts会自动换行
  83. if (sum<n) w[++m]=n-sum;
  84. num=fz(mod,module,piset);
  85. for(int i=;i<num;i++) r[i]=exlucas(n,piset[i],module[i]);
  86. printf("%lld\n",crt(num,r,module));
  87. return ;
  88. }

[bzoj2142]礼物(扩展lucas定理+中国剩余定理)的更多相关文章

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

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

  2. BZOJ1951 [Sdoi2010]古代猪文 【费马小定理 + Lucas定理 + 中国剩余定理 + 逆元递推 + 扩展欧几里得】

    题目 "在那山的那边海的那边有一群小肥猪.他们活泼又聪明,他们调皮又灵敏.他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心--" --选自猪王国民歌 很久很久以前,在山的那 ...

  3. 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最后会得到一个同余 ...

  4. [BZOJ2142]礼物(扩展Lucas)

    2142: 礼物 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2286  Solved: 1009[Submit][Status][Discuss] ...

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

  6. BZOJ 1951: [Sdoi2010]古代猪文 [Lucas定理 中国剩余定理]

    1951: [Sdoi2010]古代猪文 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 2194  Solved: 919[Submit][Status] ...

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

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

  8. BZOJ2142 礼物 扩展lucas 快速幂 数论

    原文链接http://www.cnblogs.com/zhouzhendong/p/8110015.html 题目传送门 - BZOJ2142 题意概括 小E购买了n件礼物,送给m个人,送给第i个人礼 ...

  9. 【Lucas组合数定理+中国剩余定理】Mysterious For-HDU 4373

    Mysterious For-HDU 4373 题目描述 MatRush is an ACMer from ZJUT, and he always love to create some specia ...

随机推荐

  1. EasyPlayer RTSP播放器运行出现: Unable to load DLL 找不到指定的模块。exception from HRESULT 0x8007007E 解决方案

    最近有EasyPlayer RTSP播放器的开发者反馈,在一台新装的Windows Server 2008的操作系统上运行EasyPlayer RTSP播放器出现"Unable to loa ...

  2. unity里standard pbr(一)

    关注forwardbase下的 standard.shader #pragma vertex vertBase #pragma fragment fragBase #include "Uni ...

  3. 我的Java开发学习之旅------>Java 格式化类(java.util.Formatter)基本用法

    本文参考: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html http://www.blogjava.net/ ...

  4. swift ! 和 ? 的学习

    刚开始学 这两个符号 不确定到底是否是可以互相替代 用的都混淆了 今天好好做个总结 如果声明一个变量 如下 var  name:String?  //只声明 没做初始化赋值 说明 当前name 是 n ...

  5. 手机端网页web开发要点

    1.初始化 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" c ...

  6. CSS3滑块菜单

    在线演示 本地下载

  7. web前端框架之自定义form表单验证

    自定义form验证初试 .在后端创建一个类MainForm,并且在类中自定义host ip port phone等,然后写入方法,在post方法中创建MainForm对象,并且把post方法中的sel ...

  8. 某国际知名IT公司笔试

    原文地址:http://blog.csdn.net/lazy_tiger/article/details/1790986 这段时间没怎么顾及自己的这个“一寸土地”, 实在惭愧.因为这些天小弟又经历了“ ...

  9. JAVA NIO之浅谈内存映射文件原理与DirectMemory

    JAVA类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原 ...

  10. 在线编辑代码[django]版本

    再国内,做什么都这么吃力.连aliyun 的ssh 都被封这是什么世道,所以做一个在线编辑代码的忙忙碌碌有点粗糙.大家见谅​1. [代码]views.py #-*- coding:utf-8 -*-  ...