【题解】国家集训队礼物(Lucas定理)

[国家集训队]礼物(扩展Lucas定理)

传送门可以直接戳标题
172.40.23.20 24 .1
答案就是一个式子:

[{nchoose Sigma_{i=1}^m w} imesprod_{i=1}^m {Sigma_{j=1}^m w_j-Sigma_{j=1}^{j< i}w_jchoose w_i} ]

解释一下这个式子怎么来的...

  • 先从所有的礼物里面选出(Sigma w)出来
  • 每个人依次选,选择的方案就是从剩下的礼物中挑出(w_i)

直接扩展Lucas...

#include<bits/stdc++.h>
#define int long long 
using namespace std;typedef long long ll;
template < class ccf >
inline ccf qr(ccf b){
    register char c=getchar();register int q=1;register ccf x=0;
    while(c<48||c>57)q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
    return q==-1?-x:x;}
inline int qr(){return qr(1);}


const int maxn=51;
int n,mod,m;
int w[maxn];


namespace lcs{
    inline ll poww(ll a,ll b,ll mod){
    ll base=a,ans=1;
    while(b){
        if(b&1) ans=(1ll*ans*base)%mod;
        base=(1ll*base*base)%mod;
        b>>=1;
    }
    return 1ll*ans;
    }

    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 rev(ll k,ll p){
    if(!k)return 0;
    ll x=0,y=0,a=k,b=p;
    Exgcd(a,b,x,y);
    x=(x%b+b)%b;
    if(!x)x+=b;
    return 1ll*x;
    }
    inline ll mul(ll n,ll p,ll pk){
    if(!n)return 1;
    ll ans=1;
    for(ll i=2;i<=pk;i++)
        if(i%p)ans=ans*i%pk;
    ans=poww(ans,n/pk,pk);
    for(ll i=2;i<=n%pk;i++)
        if(i%p)ans=ans*i%pk;
    return 1ll*ans*mul(n/p,p,pk)%pk;
    }
    
    inline ll C(ll n,ll m,ll mod,ll p,ll pk){
    if(m>n)return 0;
    ll a=mul(n,p,pk),b=mul(m,p,pk),c=mul(n-m,p,pk),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 ans=1ll*a*rev(b,pk)%pk*rev(c,pk)%pk*poww(p,k,pk)%pk;

    return 1ll*ans*(mod/pk)%mod*rev(mod/pk,pk)%mod;
    }
    inline ll exlucas(int n,int m){
    int mod=::mod;
    int ret=0;
    for(register int t=2;t*t<=mod;++t)
        if(mod%t==0){
        register int temp=1;
        while(mod%t==0) temp*=t,mod/=t;
        ret=(ret+C(n,m,::mod,t,temp))%(::mod);
        }
    if(mod>1) ret=(ret+C(n,m,::mod,mod,mod))%(::mod);
    return ret;
    }
    
}

using lcs::exlucas;
#undef int
int main(){
#define int long long
    // freopen("gift.in","r",stdin);
    // freopen("gift.out","w",stdout);
    mod=qr();
    n=qr();m=qr();
    for(register int t=1;t<=m;++t)
    w[t]=qr(),w[0]+=w[t];
    if(w[0]>n) return puts("Impossible"),0;
    ll ans=exlucas(n,w[0]);
    for(register int t=1;t<=m;++t)
    ans=ans*exlucas(w[0],w[t])%mod,w[0]-=w[t];
    printf("%lld
",(ll)ans);
    return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/10805414.html