题目分析
题目要求xA≡B(modP)x^A \equiv B \pmod{P}xA≡B(modP)的解的个数。
首先将PPP分解质因数,对于每个方程xA≡bi(modpiai)x^A \equiv b_i \pmod{p_i^{a_i}}xA≡bi(modpiai),求出解的个数。假设我们确定了这个方程的解,最后用中国剩余定理合并,不同方程组肯定对应不同的解,所以将每个方程的解数乘起来就是最终解的个数。
对于单个方程,分三种情况讨论。
情况1:bi=0b_i=0bi=0。
说明若将xxx写成ptqp^tqptq的形式,ttt因子的大小至少是⌈aA⌉\lceil \frac{a}{A} \rceil⌈Aa⌉,那么qqq的大小就可以取[1,pa−(⌈aA⌉)][1,p^{a-(\lceil \frac{a}{A} \rceil)}][1,pa−(⌈Aa⌉)],并且其中一些取值有ppp因子所以也会包括ttt取更大的值的情况,所以该情况下的解数是pa−(⌈aA⌉)p^{a-(\lceil \frac{a}{A} \rceil)}pa−(⌈Aa⌉)
情况2:p∣bp|bp∣b
设b=ptdb=p^tdb=ptd,则xA≡ptd(modpa)x^A \equiv p^td \pmod{p^a}xA≡ptd(modpa)。若A̸∣tA \not| tA̸∣t,则无解,否则
(xptA)A≡d(modpa−t)(\frac{x}{p^{\frac{t}{A}}})^A \equiv d \pmod{p^{a-t}}(pAtx)A≡d(modpa−t)
就转化成情况3了。
但是在情况2中,本来xptA\frac{x}{p^{\frac{t}{A}}}pAtx的取值范围是[0,pa−tA)[0,p^{a-\frac{t}{A}})[0,pa−At)的,所以解数还要乘一个pt−tAp^{t-\frac{t}{A}}pt−At
情况3:p̸∣bp \not| bp̸∣b
求出pap^apa的原根ggg(pap^apa不是质数啊,剩余系大小是ϕ(pa)\phi(p^a)ϕ(pa)啊QAQ)
那么让gr≡b(modpa)g^r \equiv b \pmod{p^a}gr≡b(modpa),rrr用BSGS求出,则根据欧拉降幂得出下面的式子,原xxx的解数是下面这个式子的解数:
Ax≡r(modpa mod ϕ(pa))Ax \equiv r \pmod{p^a \bmod{\phi(p^a)}}Ax≡r(modpamodϕ(pa))
后面那一串记作p′p'p′吧。
那么这个式子,若gcd(p′,A)̸∣rgcd(p',A) \not| rgcd(p′,A)̸∣r,无解,否则根据同余方程通解的表现形式(解出的任意xxx,x+tp′gcd(p′,A)x+t\frac{p'}{gcd(p',A)}x+tgcd(p′,A)p′),解数为gcd(p′,A)gcd(p',A)gcd(p′,A)。
代码
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int T,A,B,P,kP,ans;
int pri[100005];
int gcd(int x,int y) {return y?gcd(y,x%y):x;}
int fast_pow(int x,int y) {
int re=1;
for(;y;y>>=1,x=x*x) if(y&1) re=re*x;
return re;
}
int fast_pow(int x,int y,int p) {
int re=1;
for(;y;y>>=1,x=1LL*x*x%p) if(y&1) re=1LL*re*x%p;
return re;
}
map<int,int> mp;
int bsgs(int x,int y,int p) {
if(y==1) return 0;
mp.clear();int m=ceil(sqrt((double)p)),q=1;
for(RI i=0;i<m;++i) mp[(int)(1LL*q*y%p)]=i+1,q=1LL*q*x%p;
for(RI i=m,x=1;;i+=m) {
x=1LL*x*q%p;
if(mp[x]) return i-mp[x]+1;
if(i>p) return -1;
}
}
int getg(int x,int phi) {
int js=0,kphi=phi;
for(RI i=2;i*i<=kphi;++i)
if(kphi%i==0) {pri[++js]=i;while(kphi%i==0) kphi/=i;}
if(kphi!=1) pri[++js]=kphi;
for(RI i=2;;++i) {
int flag=1;
if(fast_pow(i,phi,x)!=1) continue;
for(RI j=1;j<=js;++j)
if(fast_pow(i,phi/pri[j],x)==1) {flag=0;break;}
if(flag) return i;
}
}
int getans(int p,int a,int kB) {
if(kB==0) return fast_pow(p,a-((a-1)/A+1));
int t=0;while(kB%p==0) kB/=p,++t;
if(t%A) return 0;
a-=t;int pa=fast_pow(p,a);
int phi=pa-pa/p,g=getg(pa,phi),r=bsgs(g,kB,pa),d=gcd(phi,A);
if(r%d) return 0;
return d*fast_pow(p,t-t/A);
}
int main()
{
scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&A,&B,&P);
P=P+P+1,kP=P,ans=1;
for(RI i=2;i*i<=kP;++i) if(kP%i==0) {
int js=0,pa=1;
while(kP%i==0) kP/=i,++js,pa*=i;
ans*=getans(i,js,B%pa);
}
if(kP!=1) ans*=getans(kP,1,B%kP);
printf("%d\n",ans);
}
return 0;
}