bzoj2142: 礼物

Posted Achen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2142: 礼物相关的知识,希望对你有一定的参考价值。

传送门

题解

扩展卢卡斯定理的模板。

技术分享图片
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
const int N=1e5+7;
typedef long long LL;
using namespace std;
LL P,n,w,ans,pp[N],pkk[N];
int m,tot; 

template<typename T> void read(T &x) {
    char ch=getchar(); x=0; T f=1;
    while(ch!=-&&(ch<0||ch>9)) ch=getchar();
    if(ch==-) f=-1,ch=getchar();
    for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f;
}

LL ksm(LL a,LL b,LL mod) {
    LL base=a,res=1;
    while(b) {
        if(b&1) res=res*base%mod;
        base=base*base%mod;
        b>>=1; 
    }    
    return res;
}

void exgcd(LL a,LL b,LL &d,LL &x,LL &y) {
    if(!b) {d=a; x=1; y=0; return;}
    exgcd(b,a%b,d,y,x); y-=a/b*x;
}

LL fac(LL n,LL p,LL pk) {
    if(!n) return 1;
    LL res,tp=1;
    for(int i=2;i<=pk;i++) if(i%p) 
        tp=tp*i%pk;
    res=ksm(tp,n/pk,pk);
    for(int i=2;i<=n%pk;i++) if(i%p) 
        res=res*i%pk;
    return res*fac(n/p,p,pk)%pk;
}

LL inv(LL n,LL pk) {
    LL d,x,y; exgcd(pk,n,d,x,y);
    return (y+pk)%pk==0?pk:(y+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),k=0;
    for(int i=n;i;i/=p) k+=i/p;
    for(int i=m;i;i/=p) k-=i/p;
    for(int i=n-m;i;i/=p) k-=i/p;
    return a*inv(b,pk)%pk*inv(c,pk)%pk*ksm(p,k,pk)%pk;
}

LL solve(LL n,LL m) {
    int sqr=sqrt(P),tot=0; 
    LL M=P,PP=P,res=0; 
    for(int i=2;i<=sqr;i++) if(P%i==0){
        tot++;
        pp[tot]=i,pkk[tot]=1;
        while(PP%i==0) {
            pkk[tot]*=pp[tot];
            PP/=i;
        }
    }
    if(PP!=1) {
        pp[++tot]=PP; pkk[tot]=PP;
    }
    for(int i=1;i<=tot;i++) {
        LL p=pp[i],pk=pkk[i];
        LL b=C(n,m,p,pk),tp=M/pk,d,x,y;
        exgcd(pk,tp,d,x,y); y=(y+M)%M;
        res=(res+tp*y%M*b%M)%M;
    }
    return res;
}

int main() {
    read(P); read(n); read(m);
    ans=1;
    for(int i=1;i<=m;i++) {
        read(w);
        (ans*=solve(n,w))%=P;
        n-=w;
        if(n<0) {
            puts("Impossible");
            return 0; 
        }
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

 

以上是关于bzoj2142: 礼物的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2142: 礼物

[BZOJ2142]礼物(扩展Lucas)

BZOJ#2142. 礼物

bzoj2142 礼物

bzoj 2142: 礼物

@bzoj - 2142@ 礼物