[国家集训队] 礼物

Description

给定P,求\(\Pi_{i=1}^m C_{n-w_1-w_2-...-w_{i-1}}^{w_i}\;mod\;P\)\(m\leq 5\)

Solution

扩展Lucas的板子。
P不是质数的话可以先质因数分解,然后求出同余每个质数次幂的解,再CRT合并就吼了
\(n!\)怎么求还是注意一下吧,要先把和\(p_i\)不互质的部分拎出来算。拎出来的代码大概就是这样

for(int i=n;i;i/=c[cur])
    now+=i/c[cur];

别的就没啥了。突然发现自己数论忘了好多,都是看的自己之前写的博客。

Code

#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
#define int long long

int p[100005],c[100005];
int P,w[10],tot,a[100005];

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

int inv(int a,int b){
    int x,y;
    exgcd(a,b,x,y);
    return (x%b+b)%b;
}

int getint(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while( isdigit(ch))X=X*10+ch-48,ch=getchar();
    return w?-X:X;
}

int ksm(int a,int b,int c){
    int ans=1;
    while(b){
        if(b&1) ans=ans*a%c;
        a=a*a%c;b>>=1;
    } return ans;
}

void fj(int P){
    int sq=sqrt(P);
    for(int i=2;i<=sq;i++){
        if(P%i==0){
            c[++tot]=i;
            while(P%i==0)
                p[tot]++,P/=i;
            p[tot]=ksm(i,p[tot],1e9+2);
        }
    } if(P!=1)
        c[++tot]=P,p[tot]=P;
}

int solve(int x,int cur){
    if(!x) return 1;
    int now=1;
    for(int i=2;i<p[cur];i++){
        if(i%c[cur])
            now=now*i%p[cur];
    }
    now=ksm(now,x/p[cur],p[cur]);
    int q=x%p[cur];
    for(int i=2;i<=q;i++){
        if(i%c[cur])
            now=now*i%p[cur];
    }
    return now*solve(x/c[cur],cur)%p[cur];
}

int C(int n,int m,int cur){
    if(n<m) return 0;
    if(n==m) return 1;
    int now=0;
    for(int i=n;i;i/=c[cur])
        now+=i/c[cur];
    for(int i=m;i;i/=c[cur])
        now-=i/c[cur];
    for(int i=n-m;i;i/=c[cur])
        now-=i/c[cur];
    int a=solve(n,cur),b=solve(m,cur),cc=solve(n-m,cur);
    return a*inv(b,p[cur])%p[cur]*inv(cc,p[cur])%p[cur]*ksm(c[cur],now,p[cur])%p[cur];
}

int CRT(){
    int ans=0;
    for(int i=1;i<=tot;i++)
        ans=(ans+a[i]*(P/p[i])*inv(P/p[i],p[i]))%P;
    return ans;
}

signed main(){
    P=getint();fj(P);
    int n=getint(),m=getint(),cnt=0;
    for(int i=1;i<=m;i++)
        w[i]=getint(),cnt+=w[i];
    if(cnt>n) return printf("Impossible"),0;
    int ans=1,sum=n;
    for(int i=1;i<=m;i++){
        for(int j=1;j<=tot;j++)
            a[j]=C(sum,w[i],j);
        // printf("CRT=%lld\n",CRT());
        ans=ans*CRT()%P;
        sum-=w[i];
    } printf("%lld\n",ans);
    return 0;
}

posted @ 2018-09-20 08:57  YoungNeal  阅读(166)  评论(0编辑  收藏  举报