快速幂 & 素数筛法

来源:互联网 发布:微信模板消息 java 编辑:程序博客网 时间:2024/06/09 21:02
// 素数表  N static int visited[N];    memset(visited, 0, sizeof(visited));    int m = sqrt(N + 0.5);    for(int i = 2; i <= m; i++)        if(!visited[i])            for(int j = i*i; j <= N; j += i)                visited[j] = 1;
// 快速幂  -> a^bLL quick_pow(LL a, LL b){    LL ret = 1;    LL temp = a;    while(b)    {        if(b & 1)            ret = ret * temp % p;        temp = temp * temp % p;        b /= 2;    }    return ret;}

M - 组合 FZU - 2020

给出组合数C(n,m), 表示从n个元素中选出m个元素的方案数。例如C(5,2) = 10, C(4,2) = 6.可是当n,m比较大的时候,C(n,m)很大!于是xiaobo希望你输出 C(n,m) mod p的值!
Input

输入数据第一行是一个正整数T,表示数据组数 (T <= 100) 接下来是T组数据,每组数据有3个正整数 n, m, p (1 <= m <= n <= 10^9, m <= 10^4, m < p < 10^9, p是素数)
Output

对于每组数据,输出一个正整数,表示C(n,m) mod p的结果。
Sample Input

2
5 2 3
5 2 61
Sample Output

1
10

/**  在求解除法取模问题(a/b)%m时,我们可以转化为(a%(b∗m))/b, 但是如果b很大,则会出现爆精度问题,所以我们避免使用除法直接计算。 可以使用逆元将除法转换为乘法: 假设b存在乘法逆元,即与m互质(充要条件)。设c是b的逆元,即b∗c≡1(modm),那么有a/b=(a/b)∗1=(a/b)∗b∗c=a∗c(modm) 即,除以一个数取模等于乘以这个数的逆元取模。逆元求解一般利用扩欧。当m为质数的时候直接使用费马小定理,m非质数使用欧拉函数。当m为质数的时候,神奇的线性方法。*/#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define LL long longusing namespace std;LL  p;LL quick_pow(LL a, LL b){    LL ret = 1;    LL temp = a;    while(b)    {        if(b & 1)            ret = ret * temp % p;        temp = temp * temp % p;        b /= 2;    }    return ret;}int main(){    static LL m, n;    int t; cin>>t;    while(t--)    {        LL a = 1, b = 1;        scanf("%lld%lld%lld", &n, &m, &p);        for(int i = 1; i <= m; i++)        {            a *= n - (m - i);            a %= p;            b *= i;            b %= p;        }        /*这里要注意 是 要对大整数 取余          本来是 (a / b) % p, 应为 b 很大 会出现爆精度的问题,运用 乘法逆元, bx 同余  1  mod   p  ,x  就是 b  的乘法逆元,又因为 p 是 素数 ,所以 x = b^(p-2), 所以 就变成了  a * x % p (将 除法运算  -》 乘法运算)         */         LL temp = quick_pow(b, p-2);        LL ans = a * temp % p;        printf("%lld\n", ans);    }    return 0;}