洛谷 P2183 [国家集训队]礼物

题目链接

扩展卢卡斯板子

#include<bits/stdc++.h>
using namespace std;

#define ll long long 

ll gcd(ll x, ll y) { return !y ? x : gcd(y, x % y); }
ll exgcd(ll a, ll b, ll &x, ll &y){
    if(!b) { x = 1; y = 0; return a; }
    ll ret = exgcd(b, a % b, y, x);
    y -= a/b * x; return ret;
}
ll ksm(ll x,ll y,ll mod){
    ll z = 1;
    while(y){
        if(y & 1) z = z * x % mod;
        y >>= 1; x = x * x % mod;
    }
    return z;
}
ll inv(ll a,ll mod){
    ll x,y; exgcd(a,mod,x,y);
    return (x % mod + mod) % mod;
}

ll f(ll n,ll p,ll p_k){
    if(n == 0) return 1;
    ll ret1 = 1, ret2 = 1;
    for(ll i = 1; i <= p_k; ++ i) if(i % p) ret1 = ret1 * i % p_k;
    ret1 = ksm(ret1, n/p_k, p_k);
    for(ll i = p_k * (n/p_k); i <= n; ++ i) if(i % p) ret2 = ret2 * (i % p_k) % p_k;
    return f(n/p, p, p_k) * ret1 % p_k * ret2 % p_k;
}
ll g(ll n, ll p){
    if(n < p) return 0;
    return g(n/p,p) + (n/p);
}
ll lucas(ll n, ll m, ll p, ll k, ll p_k){
    return f(n,p,p_k) * inv(f(m,p,p_k),p_k) % p_k * inv(f(n - m, p,p_k),p_k) % p_k * ksm(p, g(n,p) - g(m,p) - g(n - m,p), p_k) % p_k;    
}
ll exlucas(ll n, ll m, ll mod){
    ll x = mod; ll ret = 0; 
    ll A,M;
    for(ll i = 2; i * i <= x; ++ i){
        if(x % i) continue;
        
        ll tim = 0; M = 1;
        while(x % i == 0) ++ tim, x /= i, M *= i;
        A = lucas(n,m,i,tim,M);
        ret = (ret + A * (mod / M) % mod * inv(mod / M, M) % mod) % mod;
    }
    if(x > 1){
        ll A = lucas(n,m,x,1,x);
        ret = (ret + A * (mod / x) % mod * inv(mod / x, x) % mod) % mod;
    }
    return ret;
}

int P,n,m;
int main(){
    ll ans = 1;
    scanf("%d%d%d",&P,&n,&m);
    for(int i = 1; i <= m; ++ i){
        int x; scanf("%d",&x);
        if(x > n) { puts("Impossible"); return 0; }
        ans = (ans * exlucas(n,x,P) % P);
        n -= x;
    }
    printf("%lld
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/zzhzzh123/p/13438332.html