题意就是求下列的式子:
包含 CRT、Lucas、费马小定理、欧拉定理、逆元
数论全家桶(小)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int _mod = 999911659;
const int mod = 999911658;
const int MAXN = 40005;
//快速幂
inline ll ksm(ll x,ll pow,ll mod)
{
ll ans = 1;
while(pow)
{
if(pow&1) ans = ans*x % mod;
pow>>=1;
x = x*x % mod;
}
return ans;
}
//快读
inline ll read()
{
ll x=0,f=1;char ch = getchar();
while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
/*--用卢卡斯求组合数mod p --*/
//初始化阶乘与阶乘的逆元
ll fac[MAXN],inv[MAXN];
inline void init_fac(ll p) //在 mod p 下的阶乘与逆元
{
fac[0] =1;
for(int i=1;i<p;++i)
fac[i] = fac[i-1]*i % p;
//逆元
inv[p]=0;
inv[p-1] = ksm(fac[p-1],p-2,p);
for(int i=p-2;i>=0;i--)
inv[i] = inv[i+1]*(i+1)%p; //费马小定理
}
inline ll C(ll n,ll m,ll p) //在mod p 下的组合数
{
if(m>n) return 0;
return fac[n]*inv[m] %p * inv[n-m] %p ;
}
inline ll Lucas(ll n,ll m,ll p)
{
if(m==0) return 1;
return Lucas(n/p,m/p,p)*C(n%p,m%p,p) %p;
}
/*- CRT 中国剩余定理 -*/
ll a[10]; //表示CRT方程的余数ai
ll p[10]; //分解出的模数
ll cnt; //模数数量
inline void getCRT_A(ll x,ll n,ll d[],ll tot) // 求第x个余数ax , d[]为组合数m的数列 C(n,m)
{
init_fac(p[x]);
for(int i=1;i<=tot;i++)
a[x]=(a[x]+Lucas(n,d[i],p[x]))%p[x];
}
inline ll CRT(ll a[],ll p[],ll cnt) // 余数 模数 数量
{
ll M , _M, ans = 0;
//这里已有模数的积 即_mod-1 = mod
//这里是省略部分
//按公式计算
for(int i=1;i<=cnt;i++)
{
M = mod/p[i] , _M = ksm(M,p[i]-2,p[i]); //求逆元当p很大时用exgcd
ans = (ans+a[i]%mod * _M%mod * M%mod) % mod;
}
return (ans+mod)%mod; // 保留正数解
}
/*- 主程序 -*/
int main()
{
ll n,g;
n = read();
g = read();
if(g%_mod==0)
{
printf("0\n");
return 0;
}
//分解因数
ll t = mod;
for(int i=2;i*i<=mod;i++)
{
if(t%i==0)
{
p[++cnt]=i;
while(t%i==0) t/=i;
}
}
if(t!=1) p[++cnt]=t;
//求因数
ll tot = 0;
ll d[MAXN];
for(int i=1;i*i<=n;i++)
{
if(n%i==0)
{
d[++tot]=i;
if(i*i!=n) d[++tot]=n/i;
}
}
for(int i=1;i<=cnt;i++) getCRT_A(i,n,d,tot);
printf("%lld\n",ksm(g,CRT(a,p,cnt),_mod));
return 0;
}