bzoj 3122: [Sdoi2013]随机数生成器【BSGS】
题目要求的是:
\[...a(a(a(ax+b)+b)+b)+b...=a^nx+a^{n-1}b+a^{n-2}b+...+b\equiv t(mod\ p)
\]
后面这一大坨看着不舒服,所以考虑把它化掉,这里有两种做法:
做法一:两边同乘a-1
\[(a^{n-1}x)(a-1)+b(a^{n-1}-1)\equiv t(a-1)(mod\ p)
\]
\[a^nx-a^{n-1}x+ba^{n-1}-b \equiv at-t(mod\ p)
\]
\[axa^{n-1}-xa^{a-1}+ba^{n-1} \equiv at-t+b(mod\ p)
\]
\[(ax-x+b)a^{n-1} \equiv at-t+b(mod\ p)
\]
\[a^{n-1}\equiv (at-t+b)inv(ax-x+b)(mod\ p)
\]
注意这个很容易乘爆,记得随时取模
做法二:后面乘上a-1的逆元
\[a^{n-1}x+b(a^{n-1}-1)inv(a-1)\equiv t(mod\ p)
\]
\[a^{n-1}x+b*a^{n-1}*inv(a-1)-b*inv(a-1)\equiv t(mod\ p)
\]
\[a^{n-1}x+b*a^{n-1}*inv(a-1)\equiv t+b*inv(a-1)(mod\ p)
\]
\[a^{n-1}(b*inv(a-1)+x)\equiv t+b*inv(a-1)(mod\ p)
\]
\[a^{n-1}\equiv (t+b*inv(a-1))inv(b*inv(a-1)+x)(mod\ p)
\]
然后用BSGS解即可,记得加一
#include<iostream>
#include<cstdio>
#include<map>
#include<cmath>
using namespace std;
long long T,p,a,b,x,t,y,z;
map<long long,long long>mp;
long long ksm(long long a,long long b)
{
long long r=1ll;
a%=p;
while(b)
{
if(b&1)
r=r*a%p;
a=a*a%p;
b>>=1;
}
return r;
}
int main()
{
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x,&t);
if(x==t)
{
puts("1");
continue;
}
if(a==0)
{
if(b==t)
puts("2");
else
puts("-1");
continue;
}
if(a==1&&b==0)
{
puts("-1");
continue;
}
if(a==1)
{
long long now=ksm(b,p-2);
printf("%lld\n",(((t-x)%p+p)%p*now%p+p)%p+1);
continue;
}
y=a,z=((a*t%p-t+b)%p*ksm(a*x-x+b,p-2)%p+p)%p;
//y=a,z=((t+b*ksm(a-1,p-2)%p)%p*ksm((x%p+b*ksm(a-1,p-2)%p)%p,p-2))%p;//(a*t-t+b)*ksm(a*x-x+b,p-2);做法二
y%=p;
if(!y&&!z)
{
puts("1");
continue;
}
if(!y)
{
puts("-1");
continue;
}
mp.clear();
long long m=ceil(sqrt(p)),t=1;
mp[1]=m+1;
for(long long i=1;i<m;i++)
{
t=t*y%p;
if(!mp[t])
mp[t]=i;
}
long long tmp=ksm(y,p-m-1),now=1,f=0;
for(long long k=0;k<m;k++)
{
long long i=mp[z*now%p];
if(i)
{
if(i==m+1)
i=0;
printf("%lld\n",k*m+i+1);
f=1;
break;
}
now=now*tmp%p;
}
if(!f)
puts("-1");
}
return 0;
}