传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3122
我去。。做这道题快把我累死了。。
原递推式:
推导过程:
为啥复制粘贴过来画质变渣了。。
另外需要注意的一点就是在做除法的时候不能直接用逆元,
比如说(10p/2p)mod p 本来应该等于5,但是你用逆元的话就成了0,因此应该一上来先把分子分母中公共的p除尽,再用逆元
代码:
#include <cstdio>
#include <map>
#include <cmath>
#define ll long long
using namespace std;
map<ll,ll> hash;
void exgcd(ll a, ll b, ll &x, ll &y)
{
if(a%b==0){x=0;y=1;return;}
ll xx, yy;
exgcd(b,a%b,xx,yy);
x=yy;y=xx-a/b*yy;
}
ll inv(ll a, ll p)
{
ll x, y;
exgcd(a,p,x,y);
return (x%p+p)%p;
}
ll BSGS(ll A, ll B, ll p)
{
ll i, j, m, t, Am, Aj;
map<ll,ll>::iterator it;
m=sqrt(p);
hash.clear();
for(i=0,t=1;i<=m;i++,t=(t*A)%p)
if(hash.find(t)==hash.end())hash[t]=i;
for(i=1,Am=1;i<=m;i++)Am=Am*A%p;
if(Am==0)return -2;
for(i=0,t=1;i<=m;i++,t=t*Am%p)
{
Aj=B*inv(t,p)%p;
it=hash.find(Aj);
if(it!=hash.end())return m*i+it->second;
}
return -2;
}
int main()
{
ll x1, a, b, p, t, T, m, n, ans;
while(~scanf("%lld",&T))
{
while(T-->0)
{
scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
if(a==0)
{
if(x1==t)ans=0;
else if(b%p==t)ans=1;
else ans=-2;
}
else if(a!=1)
{
m=t*(a-1)+b;
n=x1*(a-1)+b;
while(m%p==0 and n%p==0 and m)m/=p,n/=p;
ans=BSGS(a,m%p*inv(n,p)%p,p);
if(n==0 and m==0)ans=0;
}
else if(b!=0)
{
m=t-x1;
n=b;
while(m%p==0 and n%p==0 and m)m/=p,n/=p;
m=(m%p+p)%p;
ans=m*inv(n,p)%p;
if(m==0 and n==0)ans=0;
}
else
{
if(x1==t)ans=0;
else ans=-2;
}
printf("%lld\n",ans+1);
}
}
return 0;
}