一道很考验数论基本功的题目,知识杂糅。
首先指数取模一般用欧拉定理降维(利用指数循环节)
而这必须满足q与mod互质,
由于mod是质数,当q==mod时,结果为0,否则q与mod互质
则可用欧拉定理的推论得到:
然后只需处理质数部分即可。
大数的组合数用lucas定理求。
但由于求多次,且模数太大,阶乘的复杂度过高,不可直接求。
我们分解999911659发现:其有4个质因子,且质数都为1.
这种数非常特殊:对其求4次,每次分别模一个质因子。
就得到一个线性同余方程,且模数互质,满足中国剩余定理的条件,直接求即可。
这是一个很巧妙的思路,可以把模数大的数通过中国剩余定理转化为多个模数表示。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 4e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,-1,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
const int mod[6]={0,2,3,4679,35617,999911659};
ll fac[M][6];
ll qpow (ll a,ll b,ll m)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%m;
a=a*a%m;
b/=2;
}
return ans;
}
ll C(ll n,ll m,ll ty)
{
ll p=mod[ty];
// cout<<"==== "<<n<<" "<<m<<" "<<ty<<endl;
if(m>n) return 0;
return fac[n][ty]*qpow(fac[m][ty]*fac[n-m][ty]%p,p-2,p)%p;
}
ll cal(ll n,ll m,int ty)
{
// cout<<"--"<<n<<" "<<m<<" "<<ty<<endl;
if(m==0)return 1;
ll p=mod[ty];
return C(n%p,m%p,ty)*cal(n/p,m/p,ty)%p;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
ll d=exgcd(b,a%b,x,y);
ll z=x;
x=y;
y=z-a/b*y;
return d;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
ll n,q;
cin>>n>>q;
ll ans[5]={0};
for(int j=1;j<=5;j++)
for(int i=0;i<=4e5;i++)
if(i==0)fac[i][j]=1;
else fac[i][j]=fac[i-1][j]*i%mod[j];
for(int i=1;i*i<=n;i++)
{
if(n%i)continue;
ll d=i;
for(int j=1;j<=4;j++)ans[j]=(ans[j]+cal(n,d,j))%mod[j];
if(i!=n/i)
{
d=n/i;
for(int j=1;j<=4;j++)ans[j]=(ans[j]+cal(n,d,j))%mod[j];
}
}
/*
x%mod[j]=ans[j]同余方程
*/
ll m=999911658;
ll tp=0;
for(int i=1;i<=4;i++)
{
// cout<<i<<" "<<ans[i]<<endl;
ll x,y,z;
ll p=mod[i];
z=m/p;
exgcd(z,p,x,y);//gcd(z,p)==1
x=(x%p+p)%p;
tp+=ans[i]*z*x;
}
tp%=m;
if(q==mod[5])cout<<0<<endl;
else
cout<<qpow(q,tp,mod[5])<<endl;
return 0;
}