题意:求\(m^{\sum{d|n\ C_n^d}}\ mod\ 999911659\)
分析:因为\(999911659\)是质数,则由欧拉定理的推论得\(m^{\sum{d|n\ C_n^d\ mod\ 999911658}}\ mod\ 999911659\)
因为\(m^{\sum{d|n\ C_n^d\ mod\ 999911658}}\)直接\(Lucas\)还是会爆,考虑将\(999911658\)质因数分解为\(2*3*4679*35617\),则可以运用\(Lucas\)定理分别求出\(\sum {d|n\ C_n^d} \mod 2/3/4679/35617\),记为\(b_1,b_2,b_3,b_4\)
然后考虑合并.我们现在得到这样一个式子:
\(\left\{\begin{aligned}x\equiv\ b_1(\mod 2) \quad\\ x\equiv\ b_2(\mod 3) \quad\\ x\equiv\ b_3(\mod 4679) \quad\\x\equiv\ b_4(\mod 35617) \quad\end{aligned}\right.\)
直接中国剩余定理求解\(x\)就行了.最后输出\(m^x \mod 999911658\)
综上我们需要用到Lucas定理(包括组合数,阶乘,逆元),中国剩余定理(包括扩欧)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read(){
LL s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
const LL mod=999911659;
LL n,m,ans,tot;
int prime[5]={0,2,3,4679,35617};
LL a[50005],b[5],jc[50005];
inline LL ksm(int a,int b,int c){
LL cnt=1;
while(b){
if(b&1)cnt=(1LL*cnt*a)%c;
a=(1LL*a*a)%c;
b>>=1;
}
return cnt;
}
inline void get_jc(int p){//计算组合数要用到阶乘
jc[0]=1;
for(int i=1;i<=p;i++)
jc[i]=(jc[i-1]*i)%p;
}
inline LL C(int n,int m,int p){//计算组合数
if(n<0||m<0||n<m)return 0;
return ((1LL*jc[n]*ksm(jc[m],p-2,p))%p*ksm(jc[n-m],p-2,p))%p;
//直接根据费马小定理 用快速幂算逆元
}
inline LL Lucas(int n,int m,int p){//Lucas模板
if(n<m)return 0;else if(n==0||m==0)return 1;
return (1LL*C(n%p,m%p,p)*Lucas(n/p,m/p,p))%p;
}
inline int exgcd(int a,int b,int &x,int &y){
if(b==0){x=1;y=0;return a;}
int d=exgcd(b,a%b,y,x);
y-=x*(a/b);
return d;
}//中国剩余定理要用到扩欧
inline void Intchina(){//中国剩余定理模板
LL M=1;
for(int i=1;i<=4;i++)M*=prime[i];
for(int i=1;i<=4;i++){
int Mi=M/prime[i],x,y;
exgcd(Mi,prime[i],x,y);
ans=((ans+Mi*x*b[i])%M+M)%M;
}
}
int main(){
n=read();m=read();
if(m%mod==0){puts("0");return 0;}//一定要特判
for(int i=1;i*i<=n;i++){//枚举n的所有约数
if(n%i==0){
a[++tot]=i;
if(i*i!=n)a[++tot]=n/i;
}
}
//分别计算mod 2 3 4679 35617的值
for(int i=1;i<=4;i++){
get_jc(prime[i]);
for(int j=1;j<=tot;j++)
b[i]=(b[i]+Lucas(n,a[j],prime[i]))%prime[i];
}
Intchina();//合并
printf("%lld\n",ksm(m,ans,mod));
return 0;
}