[国家集训队]礼物

洛咕

题意:求\(C_n^{w_1}*C_{n-w_1}^{w_2}*...*C_{n-w_1-...-w_{m-1}}^{w_{m}} \mod p\),其中\(p=p_1^{c_1}p_2^{c_2}...p_k^{c_k}\)

分析:扩展卢卡斯模板题.注意一下如果\(\sum_{i=1}^mw_i>n\),则无解

#include<bits/stdc++.h>
#define LL long long
#define rg register
using namespace std;
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
int w[10];
inline LL ksm(LL a,LL b,LL c){
    rg LL cnt=1;
    while(b){
		if(b&1)cnt=(1ll*cnt*a)%c;
		a=(1ll*a*a)%c;
		b>>=1;
    }
    return cnt;
}
inline void exgcd(LL a,LL b,LL &x,LL &y){
    if(!b){x=1;y=0;return;}
    exgcd(b,a%b,y,x);y-=(a/b)*x;
}
inline LL inv(LL a,LL b){
    rg LL x,y;exgcd(a,b,x,y);
    return (x%b+b)%b;
}
inline LL CRT(LL x,LL p,LL mod){return inv(p/mod,mod)*(p/mod)*x;}
inline LL fac(LL x,LL a,LL b){
    if(x==0)return 1;rg LL ans=1;
    for(rg int i=1;i<=b;i++)
    	if(i%a)ans*=i,ans%=b;
    ans=ksm(ans,x/b,b);
    for(rg int i=1;i<=x%b;i++)
    	if(i%a)ans*=i,ans%=b;
    return (1ll*ans*fac(x/a,a,b))%b;
}
inline LL C(LL n,LL m,LL a,LL b){
    if(n<m)return 0;
    rg LL N=fac(n,a,b),M=fac(m,a,b),NM=fac(n-m,a,b),sum=0;
    for(rg int i=n;i;i/=a)sum+=i/a;
    for(rg int i=m;i;i/=a)sum-=i/a;
    for(rg int i=n-m;i;i/=a)sum-=i/a;
    return 1ll*(N*ksm(a,sum,b))%b*(inv(M,b)*inv(NM,b))%b;
}
int main(){
    rg LL p=read(),n=read(),m=read(),sum=0;
    for(int i=1;i<=m;i++)w[i]=read(),sum+=w[i];
    if(sum>n){puts("Impossible");return 0;}
    rg LL N=n,ans=1;
    for(int i=1;i<=m;i++){
		rg LL M=p,now=0;
		for(int j=2;j*j<=p;j++){
	    	rg LL tot=1;
	    	while(M%j==0)tot*=j,M/=j;
	    	now+=CRT(C(N,w[i],j,tot),p,tot),now%=p;
		}
		if(M>1)now+=CRT(C(N,w[i],M,M),p,M),now%=p;
		ans*=now;ans%=p;
		N-=w[i];
    }
    printf("%lld\n",ans);
    return 0;
}

posted on 2019-05-07 21:47  PPXppx  阅读(110)  评论(0编辑  收藏  举报