BZOJ1951 SDOI2010 古代猪文 Lucas+CRT+逆元

题意:求${G^{\sum\limits_{d|N} {C_N^d} }}\bmod P$

题解:

设\[A = \sum\limits_{d|N} {C_N^d}  = A\bmod (P - 1) + k(P - 1)\]
由费马小定理,G^A可以直接把k(P-1)省略掉,因此问题变成求G^[A%(P-1)] mod P将P-1质因分解得到2,3,4679,35617然后将A看作未知数,先用Lucas得到四个同余方程

\[\left\{ \begin{array}{l}
A \equiv {a_1}(\bmod 2)\\
A \equiv {a_2}(\bmod 3)\\
A \equiv {a_3}(\bmod 4679)\\
A \equiv {a_4}(\bmod 35617)
\end{array} \right.\]

CRT合并求出A,然后就是快速幂了。注意G=P的时候费马小定理不成立,输出0

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

const int MAXN=40000+2;
const int P=999911658;
const int M[]={0,2,3,4679,35617};
ll N,G,sum,a[5],cnt,fac[5][MAXN],ans;

ll Quick_pow(ll a,ll b,ll p){
    a%=p;
    ll t=(b&1?a:1);

    while(b>>=1){
        a*=a,a%=p;
        if(b&1) t*=a,t%=p;
    }

    return t;
}

void Calc_fac(ll n,ll k){
    fac[k][0]=1;
    for(int i=1;i<=n;i++) fac[k][i]=(fac[k][i-1]*i)%M[k];
}

ll Calc_C(ll n,ll m,ll k){
    if(m>n) return 0;
    return fac[k][n]*Quick_pow(fac[k][m]*fac[k][n-m],M[k]-2,M[k])%M[k];
}

ll Lucas(ll n,ll m,ll k){
    if(!m) return 1;
    return (Calc_C(n%M[k],m%M[k],k)*Lucas(n/M[k],m/M[k],k))%M[k];
}

void exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1,y=0;
        return;
    }

    exgcd(b,a%b,x,y);

    ll t=x;
    x=y,y=t-a/b*y;
}

ll Calc_ni(ll n,ll p){
    ll x,y;
    exgcd(n,p,x,y);

    return (x+p)%p;
}

int main(){
    cin >> N >> G;

    for(int i=1;i<=4;i++) Calc_fac(M[i],i);

    if(G==P+1){
        cout << 0 << endl;
        return 0;
    }

    for(int i=1;i*i<=N;i++){
        if(!(N%i)){
            for(int j=1;j<=4;j++) a[j]+=Lucas(N,i,j),a[j]%=M[j];
            if(i*i!=N) for(int j=1;j<=4;j++) a[j]+=Lucas(N,N/i,j),a[j]%=M[j];
        }
    }

    for(int i=1;i<=4;i++) ans+=(((a[i]*Calc_ni(P/M[i],M[i]))%P)*(P/M[i]))%P,ans%=P;

    cout << Quick_pow(G,ans,P+1) << endl;

    return 0;
}
View Code

 

posted @ 2017-02-26 12:18  WDZRMPCBIT  阅读(109)  评论(0编辑  收藏  举报