1. 程式人生 > >BZOJ - 2142 禮物 (擴展Lucas定理)

BZOJ - 2142 禮物 (擴展Lucas定理)

.net bzoj bits 莫名其妙 main mod color unique target

擴展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 }

BZOJ - 2142 禮物 (擴展Lucas定理)