POJ 3243 Clever Y | BSGS算法完全版

时间:2023-03-10 05:04:14
POJ 3243 Clever Y | BSGS算法完全版

题目:

给你A,B,K

求最小的x满足Ax=B (mod K)


题解:

如果A,C互质请参考上一篇博客

将 Ax≡B(mod C) 看作是Ax+Cy=B方便叙述与处理.

我们将方程一直除去A,C的最大公约数进行变形,最终使得A和C互质.

将方程同除d1=gcd(A,C),得到B1=A/d1*Ax-1+C1y.有可能A和C1不互素,因此继续将方程同除d2=gcd(A,C1)得到B2=A2/d1d2*Ai-2+C2y.一直这样下去知道A和Ci互素.这里也能看出,若Bi不被gcd(A,Ci)整除则无解.

最终得到Bn=An/d1d2...dn*Ax-n+Cny,并记D=An/d1d2...dn,易证明gcd(D,Cn)=1,因此存在D的逆元,可以将最后的式子变为A x-n≡BnD-1(mod Cn),此时就能求解了.

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
typedef long long ll;
using namespace std;
ll x,z,k;
ll Gcd(ll x,ll y)
{
return y==?x:Gcd(y,x%y);
}
ll exGcd(ll a,ll b,ll &x,ll &y)
{
if (b==) return x=,y=,a;
ll r=exGcd(b,a%b,y,x);
y-=a/b*x;
return r;
}
ll inv(ll a,ll m)
{
ll x,y;
exGcd(a,m,x,y);
return (x%m+m)%m;
}
namespace Hash
{
const ll N=;
const ll H=;
struct adj
{
ll nxt,v,num,val;
}e[N];
ll head[H],ecnt=;
void init()
{
ecnt=;
memset(head,,sizeof(head));
}
void insert(ll x,ll val)
{
ll org=x;
x%=H;
for (int i=head[x];i;i=e[i].nxt)
{
if (e[i].num==org)
{
e[i].val=val;
return ;
}
}
e[++ecnt].num=org;
e[ecnt].val=val;
e[ecnt].nxt=head[x];
head[x]=ecnt;
}
ll query(ll x)
{
ll org=x;
x%=H;
for (int i=head[x];i;i=e[i].nxt)
if (e[i].num==org) return e[i].val;
return -;
}
}
ll BSGS(ll a,ll b,ll c)
{
ll cnt=,G,d=;
while ((G=Gcd(a,c))!=)
{
if (b%G!=) return -;
cnt++,b/=G,c/=G;
d=d*(a/G)%c;
}
b=b*inv(d,c)%c;
Hash::init();
ll s=sqrt(c*1.0);
ll p=;
for (int i=;i<s;i++)
{
if (p==b) return i+cnt;
Hash::insert(p*b%c,i);
p=p*a%c;
}
ll q=p,t;
for (int i=s;i-s+<=c-;i+=s)
{
t=Hash::query(q);
if (t!=-) return i-t+cnt;
q=q*p%c;
}
return -;
}
int check()
{
for (ll i=,j=;i<=;i++)
{
if (j==k)
{
printf("%lld\n",i);
return ;
}
j=j*x%z;
}
if (x==)
{
puts("No Solution");
return ;
}
return ;
}
int main()
{
while (scanf("%lld%lld%lld",&x,&z,&k) && x+z+k>)
{
x%=z,k%=z;
if (check()) continue;
ll ans=BSGS(x,k,z);
if (ans==-) puts("No Solution");
else printf("%lld\n",ans);
}
return ;
}