组合数(power oj-2419)

题意:给你 a,n,m, 求a^( C(n,m) ) )% mod,mod = 999911659。

题解:组合数取模再加上题目的数据范围是肯定要用lucas定理的,但是根据 欧拉定理可知ans = a^( C(n, m) %(mod-1) + mod-1 ) %mod,因为这里mod是一个质数,所以mod-1就不是一个质数,而lucas要求取模的模数一定是质数,所以不好直接用lucas定理。那么我们可以把mod-1分解质因数(mod-1拆成素数相乘为2*3*4679*35617,可以直接打表给出),然后用lucas定理分别求C(n, m)) % m, m = 2, 3, 4679, 35617,因为模都是互质的数,所以用中国剩余定理合并它们然后快速幂求解最后的答案即可。

需要注意: 欧拉定理的使用条件是gcd(a,mod)==1,如果a==mod则要输出0。 

附上代码:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<queue>
const int mod=999911659;
const int inf=2147483640;
typedef long long LL;
using namespace std;

int t[4]= {2,3,4679,35617};
int n,m,aa,r[4],fac[4][100010];

int power(LL a,int b,LL c)//快速幂
{
    a%=c;
    LL res=1;
    while (b)
    {
        if (b&1) res=res*a%c;
        b>>=1;
        a=a*a%c;
    }
    return res;
}
int C(int n,int m,int p) //组合数
{
    if (m<n) return 0;
    return (LL)(fac[p][m]*power((LL)fac[p][n]*fac[p][m-n],t[p]-2,t[p]))%t[p];
}
int Lucas(int n,int m,int p) //卢卡斯定理
{
    if (m==0) return 1;
    return C(n%t[p],m%t[p],p)*Lucas(n/t[p],m/t[p],p)%t[p];
}
void exgcd(int a,int b,LL &x,LL &y)//扩展欧几里得
{
    if (b==0)
    {
        x=1,y=0;
        return;
    }
    exgcd(b,a%b,y,x);
    y-=a/b*x;
}
int CRT()//中国剩余定理
{
    LL x,y,M=t[0],R=r[0];
    for (int i=1; i<4; i++)
    {
        int mm=t[i],rr=r[i];
        exgcd(M,mm,x,y);
        x=((rr-R)*x%mm+mm)%mm;
        R+=M*x;
        M*=mm;
    }
    return R;
}
int main()
{
    while(scanf("%d%d%d",&aa,&n,&m)!=EOF){
            memset(fac,0,sizeof(fac));
    memset(r,0,sizeof(r));
    if (aa==mod)
    {
        printf("0\n");
        return 0;
    }
    for (int i=0; i<4; i++)
    {
        fac[i][0]=1;
        for (int j=1; j<=t[i]; j++)
            fac[i][j]=fac[i][j-1]*j%t[i];
    }
    for (int i=0; i<4; i++)
            {
                r[i]=(r[i]+Lucas(m,n,i))%t[i];
            }
    printf("%d\n",power(aa,CRT(),mod));
}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wookaikaiko/article/details/81093605
今日推荐