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

扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正)

原理:

https://blog.csdn.net/hqddm1253679098/article/details/82897638

https://blog.csdn.net/clove_unique/article/details/54571216

感觉扩展Lucas定理和Lucas定理的复杂程度差了不止一个档次,用到了一大堆莫名其妙的函数。

另外谁能告诉我把一个很大的组合数对一个非质数取模有什么卵用

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll N=100;
 5 ll c[N],m[N],p[N],k[N],n,nn,mm[N],kk,pp;
 6 
 7 void exgcd(ll a,ll b,ll& x,ll& y,ll& g) {//扩展欧几里得
 8     if(!b)x=1,y=0,g=a;
 9     else exgcd(b,a%b,y,x,g),y-=x*(a/b);
10 }
11 ll inv(ll a,ll b) {//逆元
12     ll x,y,g;
13     exgcd(a,b,x,y,g);
14     return x%b;
15 }
16 ll Pow(ll a,ll b,ll mod) {//快速幂
17     ll ret=1;
18     for(; b; b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod;
19     return ret;
20 }
21 ll fact(ll n,ll p,ll k) {//求n!去掉质因子p后对p^k取模的值
22     if(n==0)return 1;
23     ll mod=Pow(p,k,10000000),ret=1,cnt=n/mod;
24     for(ll i=1; i<=mod; ++i)if(i%p)ret=ret*i%mod;
25     ret=Pow(ret,cnt,mod);
26     for(ll i=n-cnt*mod; i>=1; --i)if(i%p)ret=ret*i%mod;
27     return ret*fact(n/p,p,k)%mod;
28 }
29 ll C(ll n,ll m,ll p,ll k) {//求C(n,m)对p^k取模的值
30     ll mod=Pow(p,k,10000000);
31     ll ret=fact(n,p,k)*inv(fact(m,p,k),mod)%mod*inv(fact(n-m,p,k),mod)%mod;
32     ll cnt=0;
33     for(ll i=p; i<=n; i*=p)cnt+=n/i;
34     for(ll i=p; i<=m; i*=p)cnt-=m/i;
35     for(ll i=p; i<=n-m; i*=p)cnt-=(n-m)/i;
36     if(cnt<0)ret=ret*inv(Pow(p,-cnt,mod),mod)%mod;
37     else ret=ret*Pow(p,cnt,mod)%mod;
38     return ret;
39 }
40 ll CRT(ll* c,ll* m,ll n) {//扩展中国剩余定理
41     ll M=1,C=0,x,y,g;
42     for(ll i=0; i<n; ++i) {
43         exgcd(M,m[i],x,y,g);
44         if((c[i]-C)%g)return -1;
45         C=x%(m[i]/g)*((c[i]-C)/g)%(m[i]/g)*M+C;
46         M=M*m[i]/g,C%=M;
47     }
48     return (C%M+M)%M;
49 }
50 void split(ll x) {//唯一分解定理
51     n=0;
52     for(ll i=2; i*i<=x; ++i)if(x%i==0) {
53             p[n]=i,k[n]=0;
54             while(x%i==0)x/=i,k[n]++;
55             n++;
56         }
57     if(x>1)p[n]=x,k[n++]=1;
58 }
59 ll C(ll nn,ll mm,ll P) {//计算C(nn,mm)%P
60     split(P);
61     for(ll i=0; i<n; ++i)m[i]=Pow(p[i],k[i],10000000),c[i]=C(nn,mm,p[i],k[i]);
62     return CRT(c,m,n);
63 }
64 ll solve() {
65     if(accumulate(mm,mm+kk,0ll)>nn)return -1;
66     ll ret=1;
67     for(ll i=0; i<kk; ++i)ret=ret*C(nn,mm[i],pp)%pp,nn-=mm[i];
68     return ret;
69 }
70 int main() {
71     while(scanf("%lld",&pp)==1) {
72         scanf("%lld%lld",&nn,&kk);
73         for(ll i=0; i<kk; ++i)scanf("%lld",&mm[i]);
74         ll ans=solve();
75         if(!~ans)printf("Impossible\n");
76         else printf("%lld\n",ans);
77     }
78     return 0;
79 }

 

posted @ 2019-02-26 22:04  jrltx  阅读(219)  评论(0编辑  收藏  举报