一、题目
二、解法
发现 p p p很小,考虑和 p p p有关的算法。
首先想到的肯定是费马小定理吧,我们可以枚举 a x a^x ax的周期 [ 1 , p − 1 ] [1,p-1] [1,p−1],设前面的系数为 n n n,那么 n n n是可以被算出来的: n = b × i n v ( a x ) m o d p n=b\times inv(a^x)\mod p n=b×inv(ax)modp
然后 n n n还有一个限制: n = x m o d p − 1 n=x\mod p-1 n=xmodp−1
综合这两个条件,我们可以解方程,用不到中国剩余定理,直接构造即可(下面的
b
b
b表示的是上面的
b
×
i
n
v
(
a
x
)
b\times inv(a^x)
b×inv(ax)):
(
p
−
1
)
×
(
x
−
b
)
+
x
(p-1)\times(x-b)+x
(p−1)×(x−b)+x把
p
,
p
−
1
p,p-1
p,p−1带进去模就能发现它是满足条件的,设它算出来的值为
t
m
p
tmp
tmp,我们先把
t
m
p
tmp
tmp模
p
×
(
p
−
1
)
p\times(p-1)
p×(p−1),得到最小的正整数解,先和
x
x
x比大小,然后再算贡献即可,时间复杂度
O
(
n
)
O(n)
O(n)。
#include <cstdio>
#define int long long
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int a,b,c,p,x,ans;
int qkpow(int a,int b)
{
int res=1;
while(b>0)
{
if(b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
signed main()
{
a=read();b=read();p=read();x=read();
a=qkpow(a,p-2);c=p*(p-1);
for(int i=1;i<p;i++)
{
b=b*a%p;
int tmp=(p-1)*(i-b)+i;
tmp=(tmp%c+c)%c;
if(tmp<=x)
ans+=(x-tmp)/c+1;
}
printf("%lld\n",ans);
}
/*
a^x (1<=x<p)
n=b (mod p)
n=i (mod p-1)
*/