[BZOJ] 2142 礼物 (exLucas+中国剩余定理)

一句话题意:给定n,m,p;求

(p通过唯一分解后pi^ci<=1e5)

p不为素数,所以得用到exLucas(我也是今天现学的T_T)

p=p1^c1*p2^c2*......pk^ck

只要求出ans%pi^ci便可以列出来k个关于ans的同余式子,用中国剩余定理求出解即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e5+10;
ll cnt,S,P,n,m,a[7],p[N],b[N],c[N];
ll poww(ll x,ll y,ll p)
{
        ll sum=1;
        while(y)
        {
                if(y&1) sum=(sum*x)%p;
                y>>=1;
                x=(x*x)%p;
        }
        return sum;
}
ll fac(ll n,ll p,ll pk)
{
        if(!n) return 1;
        ll sum=1;
        for(ll i=1;i<pk;i++)
        {
                if(i%p)
                {
                        sum=(sum*i)%pk;
                }
        }
        sum=poww(sum,n/pk,pk);
        for(ll i=1;i<=n%pk;i++)
        {
                if(i%p)
                {
                        sum=(sum*i)%pk;
                }
        }
        return sum*fac(n/p,p,pk)%pk;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
        if(!b)
        {
                x=1;
                y=0;
                return a;
        }
        ll gcd=exgcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-a/b*y;
        return gcd;
}
ll inv(ll h,ll p)
{
        ll x,y;
        exgcd(h,p,x,y);
        return (x%p+p)%p;
}
ll C(ll n,ll m,ll p,ll pk)
{
        if(n<m) return 0;
        ll tot=0;
        ll f1,f2,f3;
        f1=fac(n,p,pk);
        f2=fac(m,p,pk);
        f3=fac(n-m,p,pk);
        for(ll i=n;i;i/=p) tot+=i/p;
        for(ll i=m;i;i/=p) tot-=i/p;
        for(ll i=n-m;i;i/=p) tot-=i/p;
        return f1*inv(f2,pk)%pk*inv(f3,pk)%pk*poww(p,tot,pk)%pk;
}
bool check(ll x)
{
        for(int i=2;i<=sqrt(x);i++)
        {
                if(x%i==0) return true;
        }
        return false;
}
void init(ll g)
{
        for(int i=2;i<=g;i++)
        {
                if(g%i) continue;
                if(check(i)) continue;
                p[++cnt]=i;
                b[cnt]=i;
                g/=i;
                while(g%i==0)
                {
                        b[cnt]*=i;
                        g/=i;
                }
        }
}
void get(int x)
{
        ll v=0;
        c[x]=C(n,S,p[x],b[x]);
        for(int i=1;i<=m;i++)
        {
                c[x]=(c[x]*C(S-v,a[i],p[x],b[x]))%b[x];
                v+=a[i];
        }
}
void China()
{
        ll ans=0;
        for(int i=1;i<=cnt;i++)
        {
                ll l=P/b[i],r=b[i],x,y;
                exgcd(l,r,x,y);
                (ans+=l*x*c[i]%P)%=P;
                ans=(ans%P+P)%P;
        }
        printf("%lld",ans);
}
int main()
{
        //freopen("1.in","r",stdin);
        scanf("%lld%lld%lld",&P,&n,&m);
        for(int i=1;i<=m;i++)
        {
                scanf("%lld",&a[i]);
                S+=a[i];
        }
        if(n<S)
        {
                puts("Impossible");
                return 0;
        }
        init(P);
        for(int i=1;i<=cnt;i++) get(i);
        China();
        return 0;
}
View Code

 

posted @ 2019-07-05 14:08  ATHOSD  阅读(118)  评论(0编辑  收藏  举报