码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-10-02 15:48:07      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:中国剩余定理   multi   ble   long   ios   剩余定理   ==   介绍   str   

题意:n件礼物,送给m个人,每人的礼物数确定,求方案数。

解题关键:由于模数不是质数,所以由唯一分解定理,

$\bmod  = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_s}}$

然后,分别求出每个组合数模每个$p_i^{{k_i}}$的值,这里可以用扩展lucas定理求解,网上的教程很多,不多做介绍,

需要注意一点:${(\frac{x}{i})^{ - 1}} \equiv {x^{ - 1}}i\bmod m$ 这是处理阶乘时的关键

最后用中国剩余定理组合一下。

最终的解为$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,P,n,m,w[10],sum,ans,x,y,module[100],r[100];
 10 
 11 ll mod_pow(ll x,ll n,ll p){
 12     ll res=1;
 13     while(n){
 14         if(n&1) res=res*x%p;
 15         x=x*x%p;
 16         n>>=1;
 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=1,y=0;
 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 1;
 32     ll ans=1;
 33     for (ll i=2;i<=pk;i++) if(i%pi) ans=ans*i%pk;
 34     ans=mod_pow(ans,n/pk,pk);
 35     for (ll i=2;i<=n%pk;i++) if(i%pi) ans=ans*i%pk;
 36     return ans*multi(n/pi,pi,pk)%pk;
 37 }
 38 
 39 
 40 ll exlucas(ll n,ll m,ll mod,ll pi,ll pk){//组合数 c(n,m)mod pk=pi^k 
 41     if(m>n) return 0;
 42     ll a=multi(n,pi,pk),b=multi(m,pi,pk),c=multi(n-m,pi,pk);
 43     ll k=0;
 44     for(ll i=n;i;i/=pi) k+=i/pi;
 45     for(ll i=m;i;i/=pi) k-=i/pi;
 46     for(ll i=n-m;i;i/=pi) k-=i/pi;
 47     return a*inv(b,pk)%pk*inv(c,pk)%pk*mod_pow(pi,k,pk)%pk;//组合数求解完毕 
 48 }
 49 
 50 ll crt(int n,ll *r,ll *m){
 51     ll M=1,ret=0;
 52     for(int i=0;i<n;i++) M*=m[i];
 53     for(int i=0;i<n;i++){
 54         ll w=M/m[i];
 55         ret+=w*inv(w,m[i])*r[i];
 56         ret%=M;
 57     }
 58     return (ret+M)%M;
 59 }
 60 /*
 61 ll excrt(int n,ll *r,ll *m){
 62     ll M=m[0],pre=r[0],d;//a是模数 
 63     for(int i=1;i<n;i++){
 64         d=extgcd(M,m[i],x,y);
 65         printf("%d\n\n%d\n\n",x,y);
 66         //x=m[i];
 67         //d=1;
 68         if((pre-r[i])%d!=0) return -1;
 69         x=(pre-r[i])/d*x%m[i];
 70         pre-=x*M;
 71         M=M/d*m[i];//lcm 
 72         pre%=M;
 73     }
 74     return (pre%M+M)%M;
 75 }
 76 */
 77 
 78 int main(){
 79     scanf("%lld",&mod);
 80     scanf("%lld%lld",&n,&m);
 81     for(int i=1;i<=m;i++) scanf("%lld",&w[i]),sum+=w[i];
 82     if(n<sum){ puts("Impossible");return 0;}//puts会自动换行 
 83     ans=1;
 84     for(int j=1;j<=m;j++){
 85         n-=w[j-1];P=mod;
 86         ll now=0;
 87         int num=0;
 88         for (ll i=2;i*i<=P;i++)//分解质因子 
 89             if (P%i==0){
 90                 ll pk=1;
 91                 while(P%i==0) pk*=i,P/=i;
 92                 r[num]=exlucas(n,w[j],mod,i,pk);
 93                 module[num]=pk;
 94                 num++;
 95             }
 96         if (P>1) r[num]=exlucas(n,w[j],mod,P,P),module[num]=P,num++;
 97         ll a1=crt(num,r,module);
 98         ans=ans*a1%mod;
 99     }
100     printf("%lld\n",ans);
101     return 0;
102 }

 

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

标签:中国剩余定理   multi   ble   long   ios   剩余定理   ==   介绍   str   

原文地址:http://www.cnblogs.com/elpsycongroo/p/7620197.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!