[BZOJ 2142]礼物(扩展Lucas定理)
Description
一年一度的圣诞节快要来到了。每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小E心目中的重要性不同,在小E心中分量越重的 人,收到的礼物会越多。小E从商店中购买了n件礼物,打算送给m个人,其中送给第i个人礼物数量为wi。请你帮忙计算出送礼物的方案数(两个方案被认为是 不同的,当且仅当存在某个人在这两种方案中收到的礼物不同)。由于方案数可能会很大,你只需要输出模P后的结果。
Solution
扩展Lucas的板子题
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; typedef long long LL; LL Mod,n,m,w; LL read() { LL x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } LL pow(LL a,LL n,LL p) { LL res=1; while(n) { if(n&1)res=(res*a)%p; a=(a*a)%p,n>>=1; } return res; } void exgcd(LL a,LL b,LL &d,LL &x,LL &y) { if(!b)d=a,x=1,y=0; else exgcd(b,a%b,d,y,x),y-=x*(a/b); } LL inv(LL a,LL p) { LL d,x,y;exgcd(a,p,d,x,y); return (x+p)%p==0?p:(x+p)%p; } LL fac(LL n,LL p,LL pk) { if(n==0)return 1; LL res=1; for(LL i=2;i<=pk;i++) if(i%p)res=(res*i)%pk; res=pow(res,n/pk,pk); for(LL i=2;i<=n%pk;i++) if(i%p)res=(res*i)%pk; return (res*fac(n/p,p,pk))%pk; } LL C(LL n,LL m,LL p,LL pk) { if(n<m)return 0; LL a=fac(n,p,pk),b=fac(m,p,pk),c=fac(n-m,p,pk); LL k=0; for(LL i=n;i;i/=p)k+=i/p; for(LL i=m;i;i/=p)k-=i/p; for(LL i=n-m;i;i/=p)k-=i/p; LL res=(((a*inv(b,pk))%pk)*inv(c,pk))%pk*pow(p,k,pk)%pk; return res*(Mod/pk)%Mod*inv(Mod/pk,pk)%Mod; } LL Lucas(LL n,LL m) { LL res=0,P=Mod; for(LL i=2;i<=P;i++) if(P%i==0) { LL pk=1; while(P%i==0)P/=i,pk*=i; res=(res+C(n,m,i,pk))%Mod; } return res; } int main() { Mod=read(),n=read(),m=read(); LL ans=1; for(int i=1;i<=m;i++) { w=read(); if(n<w){printf("Impossible");return 0;} ans=(ans*Lucas(n,w))%Mod; n-=w; } printf("%lld\n",ans); return 0; }