首先你在学扩展BSGS前需要先了解BSGS。如果你还不了解BSGS或者对BSGS有什么疑问,可以看看我的BSGS讲解,我觉得基本是全网最详细的了。
我们知道,BSGS可以解决求 ax=b(mod p) a x = b ( m o d p ) 的最小非负整数 x x ,它的应用条件是要求底数 a a 与模数 p p 互质的,那么如果不互质应该怎么办呢?这时候就要用到扩展BSGS了。
扩展BSGS是在BSGS的基础上进行一些改进。既然互质的我们会做了,我们就考虑把不互质的转化为互质的。
我们设 d=gcd(a,p) d = g c d ( a , p ) ,如果 d d 不能整除 b b ,那么只有 b=1 b = 1 时有解,即 x=0 x = 0 ,否则就无解。
首先先说明一个定理:
当 c|a且c|b且c|p c | a 且 c | b 且 c | p 时
//洛谷4195
#include
using namespace std;
long long a,b,p,x;
map<long long,long long> mp;
inline long long gcd(long long x,long long y)
{
return y?gcd(y,x%y):x;
}
inline long long ksm(long long x,long long y,long long mod)
{
long long res=1;
while(y)
{
if(y&1)
res=(res*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return res;
}
inline void exBSGS(long long a,long long b,long long p)
{
if(b==1)
{
printf("0\n");
return;
}
long long d=gcd(a,p),t=1,k=0;
while(d!=1)
{
if(b%d)
{
printf("No Solution\n");
return;
}
++k;
b/=d;
p/=d;
t=(t*(a/d))%p;//[1,k]的处理
d=gcd(a,p);
if(b==t)
{
printf("%lld\n",k);
return;
}
}
mp.clear();
long long m=ceil(sqrt(p)),ans;
for(int j=0;j<=m;++j)
{
if(j==0)
{
ans=b%p;
mp[ans]=j;
continue;
}
ans=(ans*a)%p;
mp[ans]=j;
}
long long x=ksm(a,m,p),pd=0;
ans=t;
for(int i=1;i<=m;++i)
{
ans=(ans*x)%p;
if(mp[ans])
{
x=i*m-mp[ans];
printf("%lld\n",x+k);
pd=1;
break;
}
}
if(!pd)
printf("No Solution\n");
return;
}
int main()
{
while(~scanf("%lld%lld%lld",&a,&p,&b))
{
if(a==0&&b==0&&p==0)
break;
a=a%p;
b=b%p;
exBSGS(a,b,p);
}
return 0;
}
第二种:
#include
using namespace std;
long long a,b,p,x;
map<long long,long long> mp;
inline long long gcd(long long x,long long y)
{
return y?gcd(y,x%y):x;
}
inline long long ksm(long long x,long long y,long long mod)
{
long long res=1;
while(y)
{
if(y&1)
res=(res*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return res;
}
void exgcd(long long a,long long b,long long &x,long long &y)
{
if(!b)
{
x=1;
y=0;
}
else
{
exgcd(b,a%b,y,x);
y-=a/b*x;
}
}
inline void exBSGS(long long a,long long b,long long p)
{
if(b==1)
{
printf("0\n");
return;
}
long long d=gcd(a,p),t=1,k=0;
while(d!=1)
{
if(b%d)
{
printf("No Solution\n");
return;
}
++k;
b/=d;
p/=d;
t=(t*(a/d))%p;//[1,k]的处理
d=gcd(a,p);
if(b==t)
{
printf("%lld\n",k);
return;
}
}
mp.clear();
long long m=ceil(sqrt(p)),ans,x,y;
exgcd(t,p,x,y);
x=(x%p+p)%p;
if(!x)
x+=p;
b=b*x;
for(int j=0;j<=m;++j)
{
if(j==0)
{
ans=b%p;
mp[ans]=j;
continue;
}
ans=(ans*a)%p;
mp[ans]=j;
}
long long pd=0;
ans=1;
x=ksm(a,m,p);
for(int i=1;i<=m;++i)
{
ans=(ans*x)%p;
if(mp[ans])
{
x=i*m-mp[ans];
printf("%lld\n",x+k);
pd=1;
break;
}
}
if(!pd)
printf("No Solution\n");
return;
}
int main()
{
while(~scanf("%lld%lld%lld",&a,&p,&b))
{
if(a==0&&b==0&&p==0)
break;
a=a%p;
b=b%p;
exBSGS(a,b,p);
}
return 0;
}
PS:由于我自带大常数,所以在洛谷上不开O2几乎要T了