您的位置:首页 > 其它

HDU 5446 Unknown Treasure(Lucas定理+中国剩余定理)

2015-09-13 16:44 204 查看
题意:给一个组合数C(n, m) (n, m<1e18)和 mod(mod<1e18),求这个组合数模除mod的值。

思路:先用lucas定理求出组合数模除每个质因子的解,然后用中国剩余定理来进行求解,要注意两个long long类型相乘可能会爆,要把乘法改成加法的形式。

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
typedef long long LL;
typedef long long lint;

lint p[12] ;
lint num[12] ;
LL multi_mod(LL a, LL b, LL c) {
    a %= c;
    b %= c;
    LL ret = 0;
    while(b) {
        if(b&1) {
            ret += a;
            if(ret >= c) ret -= c;
        }
        a <<= 1;
        if(a>=c) a-=c;
        b >>= 1;
    }
    return ret;
}
LL quick_mod(LL a, LL p, LL n) {
    if(p == 0) return 1;
    LL ans = quick_mod(a, p/2, n);
    ans = multi_mod(ans, ans, n);
    if(p%2 == 1) ans = multi_mod(ans, a, n);
    return ans;
} 
LL pow_mod(LL a, LL p, LL n) {
	if(p == 0) return 1;
	LL ans = pow_mod(a, p/2, n);
	ans = ans * ans % n;
	if(p%2 == 1) ans = ans * a % n;
	return ans;
} 
LL C(LL n, LL m , lint p)
{
    if(m > n) return 0;
    LL ans = 1;
    for(int i=1; i<=m; i++)
    {
        LL a = (n + i - m) % p;
        LL b = i % p;
        ans =ans* (a*pow_mod(b, p-2 , p) %p) %p ;
    }
    return ans;
}

LL Lucas(LL n, LL m , lint p )
{
    if(m == 0) return 1;
     //cout << "gan" << endl;
    return C(n % p, m % p , p) * Lucas(n / p, m / p , p) % p;
}

lint CRT( lint a[] , lint m[] , int n ){
	if(n==1) return num[0];
    lint M = 1 ;
    for( int i = 0 ; i < n ; i++ ) M = M * m[i] ;
    //cout << M << endl ;
    lint ret = 0 ;
    for( int i = 0 ; i < n ; i++ ){
        lint x  ;
        lint tmp = M / m[i] ;
        //cout <<  m[i] << tmp-2 << tmp <<  endl ;
        x = quick_mod( tmp , m[i]-2, m[i] ) ;
        //cout << x << ' ' << tmp << ' ' << M << endl ;
        lint y = multi_mod( tmp , x , M ) ;
        //cout << x * tmp % M << endl;
        y = multi_mod( tmp*x % M, num[i] , M ) ;
        ret = ( ret + y ) % M ;
        //cout << ret << endl ;
        //cout << ret <<endl;
    }
    return ( ret + M ) % M ;
}

int main()
{
    //freopen( "input.txt" , "r" , stdin ) ;
    int T;
    scanf("%d", &T);
    while(T--)
    {
        lint n , m ;
        int t ;
        scanf("%I64d%I64d%d", &n, &m, &t);
        //cout << quick_mod( 2 , 5 , 7 ) ;
        for( int i = 0 ; i < t ; i++ ){
            cin >> p[i] ;
            num[i] = Lucas( n , m , p[i] ) ;
            //cout << num[i] << endl ;
           
        }
        lint ans = CRT( num , p , t  ) ;
        printf("%I64d\n", ans );
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: