版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89636628
欢迎大家访问我的老师的OJ———caioj.cn
题目描述
传送门
(“在那山的那边海的那边有一群小肥猪。他们活泼又聪明,他们调皮又灵敏。他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心……” )xswl
思路
一句话题意:给定整数 ,计算
首先先拿部分分, 时,直接输出" ".
否则,因为
是质数,所以q,n互质。由欧拉定理的推论得:
因此我们只要求出 即可。
将 分解质因数,得到: 。
我们可以枚举 的约数 ,然后运用Lucas定理,求组合数 ,分别计算出 对 四个质数取模的结果,记为 。计算过程中,对于一个质数p,可以预处理p以内的所有阶乘以及阶乘的模p乘法逆元,从而快速计算组合数。
最后,用中国剩余定理求解线性同余方程组:
得到 的最小非负整数解 。再用快速幂求 即可。
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define ll long long
#define gc getchar()
using namespace std;
const ll P=999911659;
ll p[5]={0,2,3,4679,35617},m[5],t[5];
ll pn[5][35617][2]={{},{{1,1},{1,1}},{{1,1},{1,1},{2,2}},{{1,1},{1,1}},{{1,1},{1,1}}};
inline void qr(ll &x)
{
x=0;ll f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(ll x)
{
if(x/10)qw(x/10);
putchar(x%10+48);
}
inline ll pow_mod(ll a,ll b,ll c)
{
ll ans=1;a%=c;
b%=(c-1);//费马小定理
while(b)
{
if(b&1)ans=ans*a%c;
b>>=1;a=a*a%c;
}
return ans;
}
inline ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b){x=1;y=0;return a;}
ll tx,ty;ll d=exgcd(b,a%b,tx,ty);
x=ty;y=tx-(a/b)*ty;
return d;
}
ll C(ll d,ll n,ll i)//Lucas
{
if(d<p[i]&&n<p[i])
return pn[i][n][0]*pn[i][d][1]*pn[i][n-d][1]%p[i];
return C(d%p[i],n%p[i],i)*C(d/p[i],n/p[i],i);
}
inline void pre()
{
for(int i=2;i<p[3];i++)
{
pn[3][i][0]=pn[3][i-1][0]*i%p[3];
pn[3][i][1]=pow_mod(pn[3][i][0],p[3]-2,p[3]);
}
for(int i=2;i<p[4];i++)
{
pn[4][i][0]=pn[4][i-1][0]*i%p[4];
pn[4][i][1]=pow_mod(pn[4][i][0],p[4]-2,p[4]);
}
for(int i=1;i<=4;i++)
{
m[i]=(P-1)/p[i];
ll x,y;exgcd(m[i],p[i],x,y);
t[i]=x;
}
}
int main()
{
ll n,q;qr(n),qr(q);
q%=P;
if(!q){puts("0");return 0;}
pre();
ll a[5]={0,0,0,0,0};
for(ll d=1;d*d<=n;d++)
if(n%d==0)
{
for(int i=1;i<=4;i++)
{
a[i]=(a[i]+C(d,n,i))%p[i];
if(d*d!=n)a[i]=(a[i]+C(n/d,n,i))%p[i];
}
}
ll ans=0;
for(int i=1;i<=4;i++)
ans=(a[i]*m[i]%(P-1)*t[i]%(P-1)+ans)%(P-1);
ans=(ans+(P-1))%(P-1);
qw(pow_mod(q,ans,P));puts("");
return 0;
}