[BZOJ 1951] 古代豬文【Lucas定理/費馬小定理/中國剩餘定理/擴展歐幾里得】

[Description] 求
這裏寫圖片描述

[Solution]
容易得到,
這裏寫圖片描述

所以,重點在怎麼求

如果是p-1是個質數,我們可以用sqrt(n)的時間枚舉所有d,用Lucas定理分別計算求和即可。
但是我們發現p-1=2*3*4679*35617,並不是一個質數,所以Lucas定理不能用了嗎?並不,我們可以算出這個合式分別對2、3、4679、35617的模值,寫出四個同餘方程,再用孫子定理求解即可。注意特判g==p的情況,此時費馬小定理不成立,ans=0.

[Code]

#include<cmath>
#include<cstdio>

typedef long long ll;
const int mod=999911659;
ll prime[4]={2,3,4679,35617};
ll num[4],inver[4];

void exgcd(ll x,ll y,ll&a,ll&b){
    if(!y) a=1,b=0;
    else{ exgcd(y,x%y,b,a); b-=a*(x/y); }
}

ll pow(ll a,ll n,int p){
    ll ans=1;
    while(n){
     if(n&1) ans=ans*a%p;
     a=a*a%p; n>>=1;
    }
    return ans;
}

ll C(ll m,ll n,ll p){
    if(m<n) return 0;
    if(m==n) return 1;
    if(n>m-n) n=m-n;
    ll ans=1,cm=1,cn=1;
    for(ll i=0;i<n;i++) cm=cm*(m-i)%p,cn=cn*(n-i)%p;
    return cm*pow(cn,p-2,p)%p;
}
ll Lucas(ll m,ll n,ll p){
    if(!n) return 1;
    return (Lucas(m/p,n/p,p)*C(m%p,n%p,p))%p;
}

int get(int n){
    for(int i=1,lim=sqrt(n)+1;i<lim;i++)
         if(!(n%i)){
             for(int j=0;j<4;j++) num[j]=(num[j]+Lucas(n,i,prime[j]))%prime[j];
             if(i*i-n) for(int j=0;j<4;j++) num[j]=(num[j]+Lucas(n,n/i,prime[j]))%prime[j];
         }
    ll mul=1,ans=0;
    for(int i=0;i<4;i++) mul*=prime[i];
    for(ll i=0,t;i<4;i++){
     exgcd(mul/prime[i],prime[i],inver[i],t);
     inver[i]*=mul/prime[i];
    }
    for(int i=0;i<4;i++) ans=(ans+num[i]*inver[i])%(mod-1);
    return (ans+(mod-1))%(mod-1);
}

int main(){
    int n,g;
    scanf("%d%d",&n,&g);
    if(mod==g){ printf("0"); return 0; }
    g%=mod;
    printf("%lld",pow(g,get(n),mod));
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章