思路:
费马小定理。
n*a^n = b (mod p)
根据费马小定理 a^(p-1) = 1 (mod p)
我们把n化为 n=i+y(p-1)
于是[i+y(p-1)]*a^ [i+y(p-1)] = b (mod p)
再根据费马小定理a^ [i+y(p-1)]=a^i (mod p)
于是[i+y(p-1)]*a^i = b (mod p)
于是y = (b/(a^i)-i)/(p-1) (mod p)
于是y = (b/(a^i)-i)/(p-1) +k*p(除法用逆元做)
我们发现如果i>p,那么mod p 后还是在0 到 p-1的范围内,所以 0<=i<p,又因为i=0不满足题意,于是0<i<p
于是题目就转换成了遍历i,对于每个i,找有多少个y满足题意
因为n<=x,所以i+y*(p-1)<=x,所以y<=(x-i)/(p-1),所以对于每个i的y的上界可以确定,找y的个数就很简单了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
long long a,b,p,x;
long long ans;
long long powd(long long c,long long d)
{
long long anss=1;
while(d>0)
{
if(d%2==1)
anss=anss*c%p;
c=c*c%p;
d/=2;
}
return anss;
}
long long inv(long long x)
{
return powd(x,p-2);
}
int main() {
while(~scanf("%lld%lld%lld%lld",&a,&b,&p,&x))
{
ans=0;
long long ac=1;
for(long long c=0;c<p-1;c++)
{
long long k=(c-b*inv(ac))%p;
k=(k+p)%p;
long long sta=k;
long long end=(x-c)/(p-1);
long long tans=(end-sta)/p + 1;
if(sta==0 && c==0)
tans--;
if(x<c|| end<sta || tans<0)
tans=0;
ans+=tans;
ac=ac*a%p;
}
printf("%lld\n",ans);
}
return 0;
}