luogu 2480 古代猪文 数论合集(CRT+Lucas+qpow+逆元)

一句话题意:G 的 sigma d|n  C(n d) 次幂  mod 999911659

(我好辣鸡呀还是不会mathjax)

分析:

1.利用欧拉定理简化模运算 ,将上方幂设为x,则x=原式mod 999911658.

2.发现幂的前半部分太大无法直接算,又因为999911658 可分解为 2 3 4679 35617 四个质数

3.利用中国剩余定理可分别计算 x=a1(mod m1=2) ...最后利用它统计出x

4.快速幂将答案计算

#include<bits/stdc++.h>
#define int long long 
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
using namespace std;

const int mod=999911659;

int n,g,m[6]={0,2,3,4679,35617},a[6];
int fac[50050][5];

inline int qpow(int a,int n,int p){
    int s=1;while(n){if(n&1) s=s*a%p;a=a*a%p;n>>=1;}return s;}
    
inline void init(){
    fac[0][1]=fac[0][2]=fac[0][3]=fac[0][4]=1;
    rep(i,1,50000)rep(j,1,4)
    fac[i][j]=fac[i-1][j]*i%m[j];}

inline int C(int a,int b,int c){
    if(a<b) return 0;
    return fac[a][c]*qpow(fac[b][c],m[c]-2,m[c])%m[c]*qpow(fac[a-b][c],m[c]-2,m[c])%m[c]; }
    
inline int Lucas(int a,int b,int c){
    if(!b) return 1;
    return C(a%m[c],b%m[c],c)*Lucas(a/m[c],b/m[c],c)%m[c];}

inline void work(int i){
    rep(j,1,4) a[j]=(a[j]+Lucas(n,i,j))%m[j];}
    
inline int CRT(){ int x=0,M=mod-1;
    rep(i,1,4){ int Mi=M/m[i];
    x=(x+a[i]*Mi*qpow(Mi,m[i]-2,m[i])%M)%M;}return x;}

#undef int
int main(){
#define int long long
    scanf("%lld%lld",&n,&g); init();
    if(g%mod==0) {printf("0");return 0;} 
    
    rep(i,1,sqrt(n))
        if(n%i==0){ work(i);
        if(i*i!=n) work(n/i);}
    
    printf("%lld\n",qpow(g,CRT(),mod));return 0;
}

 

posted @ 2018-10-09 08:14  ASDIC减除  阅读(238)  评论(0编辑  收藏  举报