組合數(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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章