hdu 5446 Unknown Treasure 中国剩余定理+lucas

题目链接

求C(n, m)%p的值, n, m<=1e18, p = p1*p2*...pk. pi是质数。

先求出C(n, m)%pi的值, 然后这就是一个同余的式子。 用中国剩余定理求解。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long
ll a[17], b[17];
void extend_Euclid(ll a, ll b, ll &x, ll &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    extend_Euclid(b, a % b, x, y);
    ll tmp = x;
    x = y;
    y = tmp - (a / b) * y;
}
ll mul(ll a, ll n, ll mod)
{
    a = (a%mod+mod)%mod;
    n = (n%mod+mod)%mod;
    ll ret = 0;
    while(n) {
        if(n&1)
            ret = (ret+a)%mod;
        a = (a+a)%mod;
        n >>= 1;
    }
    return ret;
}
ll CRT(ll a[],ll m[],int n)
{
    ll M = 1;
    ll ans = 0;
    for(int i=1; i<=n; i++)
        M *= m[i];
    for(int i=1; i<=n; i++)
    {
        ll x, y;
        ll Mi = M / m[i];
        extend_Euclid(Mi, m[i], x, y);
        ans = (ans + mul(mul(Mi, x, M), a[i], M))%M;
    }
    return (ans+M)%M;
}
ll pow(ll a, ll b, ll mod)
{
    ll ret = 1;
    while(b) {
        if(b&1) ret = ret*a%mod;
        a = a*a%mod;
        b /= 2;
    }
    return ret;
}
ll C(ll n, ll m, ll mod)
{
    ll a = 1, b = 1;
    for(int i = 1; i <= m; i++) {
        b = b*i%mod;
        a = a*(n-i+1)%mod;
    }
    return a*pow(b, mod-2, mod)%mod;
}
ll lucas(ll n, ll m, ll mod)
{
    if(m == 0)
        return 1;
    return lucas(n/mod, m/mod, mod)*C(n%mod, m%mod, mod)%mod;
}
int main()
{
    ll t, n, m, k;
    cin>>t;
    while(t--) {
        cin>>n>>m>>k;
        for(int i = 1; i <= k; i++) {
            scanf("%lld", &a[i]);
        }
        for(int i = 1; i <= k; i++) {
            b[i] = lucas(n, m, a[i]);
        }
        ll ans = CRT(b, a, k);
        cout<<ans<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yohaha/p/5722439.html