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;
}

 

posted @ 2018-11-05 20:18  AKCqhzdy  阅读(136)  评论(0编辑  收藏  举报