bzoj2142: 礼物
拓展Lucas板子放一手
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; typedef pair<int,int> pa; int mod; int plen,p[30],mip[30]; void emmmm() { int k=mod; for(int i=2;i*i<=mod;i++) if(k%i==0) { p[++plen]=i,mip[plen]=1; while(k%i==0)k/=i,mip[plen]*=i; } if(k!=1)p[++plen]=k,mip[plen]=k; } //~~~~~~~~~~~~~~~~~~~分解mod~~~~~~~~~~~~~~~~~~~~~ void exgcd(int a,int b,int &x,int &y) { if(a==0) { x=0,y=1; return ; } else { int tx,ty; exgcd(b%a,a,tx,ty); x=ty-b/a*tx; y=tx; } } LL inv(int A,int B)//不是质数不能用快速幂求逆元!! { int x,y; exgcd(A,B,x,y); return (x%B+B)%B; } //~~~~~~~~~~~~~~~getinv(mod p)~~~~~~~~~~~~~~~~~~~~~~~~ LL quick_pow(int A,int p,int mo) { int ret=1; while(p!=0) { if(p%2==1)ret=(LL)ret*A%mo; A=(LL)A*A%mo;p/=2; } return ret; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //-----------------------------------------init----------------------------------------------------------------- pa solve(int n,int id)//first p[id]因子个数,second n!除了这些因子的值 { if(n==0)return make_pair(0,1); LL ans=1; int d=n/mip[id]; if(d>0) { for(int i=2;i<mip[id];i++) if(i%p[id]!=0)ans=ans*i%mip[id]; ans=quick_pow(ans,d,mip[id]); } for(int i=d*mip[id]+1;i<=n;i++) if(i%p[id]!=0)ans=ans*i%mip[id]; pa t=solve(n/p[id],id); return make_pair(n/p[id]+t.first,ans*t.second%mip[id]); } LL calc(int n,int m,int id) { if(n<m)return 0; pa a=solve(n,id),b=solve(m,id),c=solve(n-m,id); LL t1=quick_pow(p[id],a.first-b.first-c.first,mip[id])*a.second%mip[id]; LL t2=inv(b.second,mip[id])%mip[id]; LL t3=inv(c.second,mip[id])%mip[id]; return t1*t2*t3%mip[id]; } LL aa[30]; LL crt() { int M=mod,ret=0; for(int i=1;i<=plen;i++) ret=(ret+aa[i]*(M/mip[i])%mod*inv(M/mip[i],mip[i])%mod)%mod; return ret; } LL exlucas(int n,int m) { for(int i=1;i<=plen;i++)aa[i]=calc(n,m,i); return crt(); } //-------------------------------------getC----------------------------------------------- int w[30]; int main() { int n,m,s=0,x; scanf("%d%d%d",&mod,&n,&m);emmmm(); for(int i=1;i<=m;i++) scanf("%d",&w[i]), s+=w[i]; if(s>n){printf("Impossible\n");return 0;} LL ans=exlucas(n,s); for(int i=1;i<=m;i++) ans=ans*exlucas(s,w[i])%mod, s-=w[i]; printf("%d\n",ans); return 0; }
pain and happy in the cruel world.