标签:中国剩余定理 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