1. 程式人生 > >2018.10.19每天認真做一道數學(數論)題之BZOJ 1951 [Sdoi2010]古代豬文【數論板子】【尤拉定理】【Lucas】【CRT】

2018.10.19每天認真做一道數學(數論)題之BZOJ 1951 [Sdoi2010]古代豬文【數論板子】【尤拉定理】【Lucas】【CRT】

由題意:
a n s = q d

n C n d   
( m o d    999911659 ) ans=q^{\sum_{d|n}C_n^d}\ \ (mod\ \ 999911659)

由於 999911659 999911659 是一個質數,我們接下來分兩類討論:

  1. q = = 999911659 q==999911659 ,顯然 a n s = 0 ans=0
  2. q ! = 999911659 q!=999911659 ,於是 g c d ( q , 999911659 ) = = 1 gcd(q,999911659)==1 ,由尤拉定理得到:
    a n s = q d n C n d    m o d    999911658    ( m o d    999911659 ) ans=q^{\sum_{d|n}C_n^d\ \ mod\ \ 999911658}\ \ (mod\ \ 999911659)

注意到: 999911658 = 2 3 4679 35617 999911658=2*3*4679*35617

於是我們接下來我們列舉 d d ,即 n n 的約數,用 L u c a s Lucas 求出 C n d C_n^d ,分別計算 d C n d \sum_{d}C_n^d 2 , 3 , 4679 , 35617 2,3,4679,35617 取模的結果,我們記為 a 1 , a 2 , a 3 , a 4 a_1,a_2,a_3,a_4

x = d C n d x=\sum_{d}C_n^d ,則有:
{ x a 1    ( m o d    2 ) x a 2    ( m o d    3 ) x a 3    ( m o d    4679 ) x a 4    ( m o d    35617 ) \begin{cases} x\equiv a_1\ \ (mod\ \ 2)\\ x\equiv a_2\ \ (mod\ \ 3)\\ x\equiv a_3\ \ (mod\ \ 4679)\\ x\equiv a_4\ \ (mod\ \ 35617)\\ \end{cases}

由於 2 , 3 , 4679 , 35617 2,3,4679,35617 兩兩互質,我們可以通過剩餘定理求出 x x

於是 a n s = q x    ( m o d    999911659 ) ans=q^x\ \ (mod\ \ 999911659)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define db double
#define sg string
#define ll long long
#define rel(i,x,y) for(ll i=(x);i<(y);i++)
#define rep(i,x,y) for(ll i=(x);i<=(y);i++)
#define red(i,x,y) for(ll i=(x);i>=(y);i--)
using namespace std;
 
const ll N=1e5+5;
const ll Mod=999911659;
 
ll n,q,ans;
ll a[5],m[5]={0,2,3,4679,35617};
 
inline ll read() {
    ll x=0;char ch=getchar();bool f=0;
    while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?-x:x;
}
 
inline ll ksm(ll a,ll b,ll p) {
    ll ret=1%p;
     
    while(b) {
        if(b&1) ret=ret*a%p;
        b>>=1;a=a*a%p;
    }
     
    return ret;
}
 
ll C(ll a,ll b,ll p) {
    ll A=1,B=1;
    if(a<b) return 0;
    else if(a==b) return 1;
     
    if(b>a-b) b=a-b;
     
    rel(i,0,b) {
        A=A*(a-i)%p;
        B=B*(b-i)%p;
    }
     
    return A*ksm(B,p-2,p)%p;
}
 
ll lucas(ll n,ll m,ll p) {
    return m==0?1:C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
 
void exgcd(ll a,ll b,ll &gcd,ll &x,ll &y) {
    if(b==0) {
        x=1;y=0;gcd=a;return ;
    }exgcd(b,a%b,gcd,x,y);
    ll ret=x;x=y;y=ret-a/b*y;
}
 
void crt() { 
    ll mm=1; 
    rep(i,1,4) mm*=m[i];
     
    rep(i,1,4) { 
        ll x,y,gcd;
        ll mi=mm/m[i]; 
        exgcd(mi,m[i],gcd,x,y); 
        ans=(ans+x*mi*a[i])%mm; 
    } 
     
    ans=(ans%mm+mm)%mm; 
}
 
int main(){
    n=read(),q=read();
     
    if(q==999911659) {
        puts("0");return 0;
    }
     
    ll s=sqrt(n);
     
    rep(i,1,s) if(n%i==0) {
        if(i*i!=n) {
            rep(j,1,4) a[j]+=lucas(n,i,m[j])+lucas(n,n/i,m[j]);
        } else {
            rep(j,1,4) a[j]+=lucas(n,i,m[j]);
        }
    }
     
    crt();
     
    printf("%lld\n",ksm(q,ans,Mod));
     
    return 0;
}