problem
给定 n , g n,g n,g,求 g ∑ d ∣ n C n d g^{\sum_{d|n}C_n^d} g∑d∣nCnd 对 999911659 999911659 999911659 取模的结果。
数据范围: 1 ≤ n , g ≤ 1 0 9 1 \le n,g \le 10^9 1≤n,g≤109。
solution
考虑直接算指数,我们要求的是 ∑ d ∣ n C n d \sum_{d|n}C_n^d ∑d∣nCnd。
根据费马小定律降幂,我们要对 999911658 999911658 999911658 取模,它不是质数,不存在逆元,怎么办呢?
对其质因数分解: 999911658 = 2 × 3 × 4679 × 35617 999911658=2\times3\times4679\times35617 999911658=2×3×4679×35617。
那么就比较显然了,我们可以先分别求出以这几个质数为模数的答案,最后 CRT \texttt{CRT} CRT 合并答案。
由于这几个模数都比较小,可以用 Lucas 定理在 O ( log n ) O(\log n) O(logn) 的时间内求组合数。
然后就 O ( n ) O(\sqrt n) O(n) 枚举约数算答案即可。
时间复杂度 O ( n log n ) O(\sqrt n \log n) O(nlogn)。
code
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5,mod=999911659;
int P,fac[N],ifac[N],a[4],p[4]={2,3,4679,35617};
int add(int x,int y) {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y) {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y) {return 1ll*x*y>=P?1ll*x*y%P:x*y;}
int power(int a,int b){
int ans=1;
for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a);
return ans;
}
void exgcd(int a,int b,int &x,int &y){
if(!b) {x=1,y=0;return;}
exgcd(b,a%b,y,x),y-=a/b*x;
}
int C(int n,int m) {return n<m?0:mul(fac[n],mul(ifac[m],ifac[n-m]));}
int Lucas(int n,int m){
if(n<P&&m<P) return C(n,m);
return mul(Lucas(n/P,m/P),C(n%P,m%P));
}
void prework(){
fac[0]=fac[1]=1;
for(int i=2;i<P;++i) fac[i]=mul(fac[i-1],i);
ifac[P-1]=power(fac[P-1],P-2);
for(int i=P-2;~i;--i) ifac[i]=mul(ifac[i+1],i+1);
}
int CRT(int ans=0){
P=mod-1;
for(int i=0;i<4;++i){
int x,y,now=P/p[i];
exgcd(now,p[i],x,y),x=(x+p[i])%p[i];
ans=add(ans,mul(a[i],mul(x,now)));
}
return ans;
}
int n,g;
int main(){
scanf("%d%d",&n,&g);
if(g==mod) return puts("0"),0;
for(int j=0;j<4;++j){
P=p[j],prework();
for(int i=1;i*i<=n;++i)if(n%i==0){
a[j]=add(a[j],Lucas(n,i));
if(i*i!=n) a[j]=add(a[j],Lucas(n,n/i));
}
}
int exp=CRT();
P=mod,printf("%d\n",power(g,exp));
return 0;
}