关于BSGS算法
文章中提到的p,如果不加说明则默认为素数。
BSGS算法适用于在求解形如ax≡b(modp)a^x\equiv b \pmod pax≡b(modp)的不等式。
可知0≤x<p0\le x<p0≤x<p,那么可以令x=A⌈p⌉−B,0<=A,B<=⌈p⌉x=A\lceil\sqrt{p}\rceil-B,0<=A,B<=\lceil\sqrt{p}\rceilx=A⌈p⌉−B,0<=A,B<=⌈p⌉
所以原问题转换成
aA⌈p⌉−B≡b mod pa^{A\lceil\sqrt{p}\rceil-B}\equiv b\bmod p\newlineaA⌈p⌉−B≡bmodp
即
aA⌈p⌉≡b∗aB mod pa^{A\lceil\sqrt{p}\rceil}\equiv b*a^B\bmod paA⌈p⌉≡b∗aBmodp
在O(sqrt(p ))内枚举等式右边的值并储存到哈希表中,然后在O(sqrt(p ))内枚举等式左边的值并在哈希表内查询,等式成立,则有x=A⌈p⌉−Bx=A\lceil\sqrt{p}\rceil-Bx=A⌈p⌉−B$。
BSGS算法也可以处理形如xi+1≡a∗xi+b(modp),求t≡xansx_{i+1}\equiv a*x_i+b \pmod{p} , 求t\equiv x_{ans}xi+1≡a∗xi+b(modp),求t≡xans
之类的问题,只需将上述数列转换成等比数列
xi+1+ba−1≡a∗(xi+ba−1)(modp),a>1x_{i+1}+\frac{b}{a-1}\equiv a*(x_i+\frac{b}{a-1}) \pmod{p},a>1 xi+1+a−1b≡a∗(xi+a−1b)(modp),a>1
那么
xn+ba−1≡an−1(x1+ba−1)(modp)x_{n}+\frac{b}{a-1}\equiv a^{n-1}(x_1+\frac{b}{a-1}) \pmod{p} xn+a−1b≡an−1(x1+a−1b)(modp)
因为要求t≡xanst\equiv x_{ans}t≡xans ,所以上述等式可以转化为
(t+ba−1)∗rev(x1+ba−1)≡aans−1(modp)(t+\frac{b}{a-1})*rev(x_1+\frac{b}{a-1})\equiv a^{ans-1} \pmod{p} (t+a−1b)∗rev(x1+a−1b)≡aans−1(modp)
只有ans是未知的,所以转化为文章开头所讲的问题。
要注意如果x1+ba−1=0x_1+\frac{b}{a-1}=0x1+a−1b=0的话,则没有逆元。这种情况同a<1的情况需要特殊处理。
当然BSGS算法经过一些改动可以处理p不为素数的情况,但本文不敞开论述。
附上一道题目
SDOI 2013(随机数生成器)
AC代码如下:
#include<bits/stdc++.h>//注意0不在乘法群中,因为0元没有逆元
using namespace std;
const int max_n=1e6;
const int HashMod=1e5;
typedef long long ll;
struct Hash_Map{
struct Line{int k;int v;int next;}e[max_n];
int HashMap[HashMod],cnt;
void init(void)
{
memset(HashMap,-1,sizeof(HashMap));
cnt=0;
}
void add(int key,int value,int hashkey)
{
e[cnt++]=Line{key,value,HashMap[hashkey]};
HashMap[hashkey]=cnt-1;
}
void insert(int key,int value)
{
add(key,value,key%HashMod);
}
int find(int key)
{
for(int i=HashMap[key%HashMod];i!=-1;i=e[i].next)
if(e[i].k==key)return e[i].v;
return -1;
}
}mp;
ll qpow(ll a,ll n,ll p)
{
ll ans=1;
while(n)
{
if(n&1)ans=ans*a%p;
a=a*a%p;
n>>=1;
}
return ans;
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b){
x=1,y=0;return ;
}
else{
exgcd(b,a%b,y,x);y-=(a/b)*x;return ;
}
}
ll rev(ll a,ll p)
{
ll t,t0;
exgcd(a,p,t,t0);
return (t+p)%p;
}
ll BSGS(ll a,ll b,ll p)
{
a%=p;b%=p;
if(b==1)return 0;
mp.init();
ll m=ceil(sqrt(p));
for(ll i=0,ret=b;i<=m;i++)
{
mp.insert(ret,i);
ret=ret*a%p;
}
ll t=qpow(a,m,p);
for(ll i=1,ret=t;i<=m;i++)
{
int f=mp.find(ret);
if(f>=0)return i*m-f;
ret=ret*t%p;
}
return -1;
}
int main(void)
{
freopen("out.txt","w",stdout);
int t0;
scanf("%d",&t0);
ll p,a,b,x,t;
while(t0--)
{
scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x,&t);
a%=p;b%=p;t%=p;x%=p;
ll ans;
if(a==0){
if(t==x)ans=1;
else if(t==b)ans=2;
else ans=-1;
}
else if(a==1&&b!=0){
ans=(((t-x)+p)%p*rev(b,p)%p+1)%p;
if(!ans)ans=p;
}
else if(a==1&&b==0){
if(x==t)ans=1;
else ans=-1;
}
else if(a>1){
int temp=b*rev(a-1,p)%p;
if(x+temp==0){
if(t==0)ans=0;
else ans=-1;
}
else ans=BSGS(a,(t+temp)%p*rev(x+temp%p,p)%p,p);
if(ans!=-1)ans+=1;
}
printf("%lld\n",ans);
}
fclose(stdout);
return 0;
}
BSGS算法是一种在解决模线性同余方程ax ≡ b (mod p)时的有效方法,尤其当p为素数。通过转换,将原问题转化为等比数列的形式,能在O(sqrt(p))的时间复杂度内求解。该算法还能应用于处理等比数列的求解。文章提到了特殊情况的处理,如x1 + (a-1)b = 0时的逆元问题,并提供了一个SDOI 2013比赛中的实际应用题目及AC代码示例。
946

被折叠的 条评论
为什么被折叠?



