前言:
今天高一hu测,出了一道exbsgs
(还让我帮忙造数据,然而我造的数据特别水,暴力都可以跑过,最后还是澍神帮了忙。。。)
然而并不会,以为又要花时间学习新知识了,
DP却和我说有一种奇技淫巧,因此就来填坑了。。。
以前学过bsgs
当时我们是这么化的式子:
x^y(mod p)=z
y=km+i(m=sqrt§)
处理出: x^i,扔进一个map中
x
i
=
z
∗
x
−
k
m
x^i=z*x^{-km}
xi=z∗x−km (mod p)
当p为质数的时候,我们可以计算出x^km的逆元
枚举k,在map中查找即可
ll bsgs(ll x,ll z,ll p)
{
mp.clear();
x%=p;
if (x==0&&z==0) return 0;
if (x==0) return -1;
ll m=(ll)ceil(sqrt((double)p)),now=1;
mp[1]=m+1;
for (int i=1;i<m;i++)
{
now=(now*x)%mod;
if (!mp[now]) mp[now]=i;
}
ll inv=1,tmp=KSM(x,p-m-1,p);
for (int k=0;k<m;k++)
{
int i=mp[(z*inv)%p];
if (i)
{
if (i==m+1) i=0;
return k*m+i;
}
inv=(inv*tmp)%p;
}
return -1;
}
然而,当p不是质数的时候,
我们就没有办法求逆元了
因此我们要改变一下式子的化简方式:
令
y
=
k
m
−
i
y=km−i
y=km−i,
m
=
s
q
r
t
(
p
)
m=sqrt(p)
m=sqrt(p),则
(
x
m
)
k
∗
x
−
i
≡
z
(
m
o
d
p
)
(x^m)^k*x^{-i}≡z(mod p)
(xm)k∗x−i≡z(modp)
移项,得
(
x
m
)
k
≡
z
∗
x
i
(
m
o
d
p
)
(x^m)^k≡z*x^i(mod p)
(xm)k≡z∗xi(modp)
首先,从0−m枚举
i
i
i,将得到的
z
∗
x
i
z*x^i
z∗xi的值存入hash表;
然后,从1−m枚举k,计算
(
a
m
)
i
(a^m)^i
(am)i,查表,如果有值与之相等,则当时得到的
k
m
−
i
km−i
km−i是最小值
注意:
k
k
k不能为0,否则
k
m
−
i
km−i
km−i有可能出现负数的情况
为了让
k
m
−
i
km−i
km−i最小,我们在hash表中记录的应该是
i
i
i的最大值
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
ll a,b,c;
map<ll,int> mp;
ll KSM(ll a,ll b)
{
ll t=1;
while (b)
{
if (b&1) t=(t%c*a%c)%c;
b>>=1;
a=(a%c*a%c)%c;
}
return t%c;
}
int bsgs(ll x,ll z)
{
mp.clear();
x%=c;
if (!x&&!z) return 1;
if (!z) return -1;
ll m=(ll)ceil(sqrt((double)c)),now=z%c;
mp[now]=m+1;
for (int i=1;i<=m;i++) //z*x^i
{
now=(now%c*x%c)%c;
mp[now]=i;
}
ll num=1,tmp=KSM(x,m);
for (int k=1;k<=m;k++)
{
num=(num*tmp)%c; //
int i=mp[num];
if (i)
{
if (i==m+1) i=0;
return (k*m-i+c)%c;
}
}
return -1;
}
int main()
{
while (scanf("%lld%lld%lld",&a,&b,&c)!=EOF&&(a+b+c)!=0)
{
int ans=bsgs(a,b);
if (ans==-1) printf("No Solution\n");
else printf("%d\n",ans);
}
return 0;
}