Shank's Baby-Step-Giant-Step Algorithm(BSGS,大步小步演算法)
阿新 • • 發佈:2018-12-14
簡介
大步小步演算法用於解決離散對數問題。即求模方程的最小解(或者給出無解)。
先討論為奇素數的情況。
暴力求解?
列舉,判斷是否與模同餘即可。
但是無解的情況如何判定?
實際上,若的情況都無解,即可判斷此方程無解。理由如下:
我們知道:因為,根據尤拉定理:由於,所以,所以當取時,至少會形成一個迴圈節。
時間複雜度
BSGS演算法
取。
- 先算出所有的,判斷是否有解,並把的值扔進表裡。
- 若無解,則考慮。
可以把拆成的形式。
那麼:
移項得:
那麼先預處理出的逆元,再列舉,判斷是否存在,若存在,則答案為
時間複雜度為
(如果不是奇素數,但滿足呢?)
將變為?
求的時間複雜度是,所以複雜度還是沒有變。。。
還是老老實實取吧。
時間複雜度
模板題
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define LL long long
int read()
{
int x = 0; char ch = getchar();
for(;ch<'0'||ch>'9';ch = getchar());
for(;ch>='0'&&ch<='9';ch = getchar()) x = (x<<3)+(x<<1)+(ch^48);
return x;
}
LL Pow(LL x,int a,LL p)
{
if(a == 0) return 1;
if(a == 1) return x;
LL y = Pow(x,a>>1,p);
y = (y * y)%p;
if(a & 1) y = (y * x)%p;
return y;
}
#define hash_mod 10000037
int head[hash_mod],ne[hash_mod],ha[hash_mod],val[hash_mod],tot;
void hash_insert(int x,int pos)
{
int y = x % hash_mod;
for(int i=head[y];i;i=ne[i])
if(ha[i] == x)
return;
ha[++tot] = x;
val[tot] = pos;
ne[tot] = head[y];
head[y] = tot;
}
int hash_find(int x)
{
int y = x % hash_mod;
for(int i=head[y];i;i=ne[i])
if(ha[i] == x)
return val[i];
return -1;
}
int BSGS(int a,int b,int p)//a^x=b(mod p)
{
int m = ceil(sqrt(p));
int num = 1;
for(int i=0;i<=m;i++)
{
hash_insert(num,i);
if(num == b) return i;
num = (1ll*num * a)%p;
}
int inv = Pow(Pow(a,m,p),p-2,p);
for(int i=1;i<=m;i++)
{
b = (1ll*b*inv)%p;
int j = hash_find(b);
if(j != -1) return i * m + j;
}
return -1;
}
int p,a,b;
int ans;
int main()
{
p = read(); a = read(); b = read();
ans = BSGS(a,b,p);
if(ans == -1) printf("no solution");
else printf("%d",ans);
return 0;
}
擴充套件
若呢?
這時就要用到擴充套件了。
我們考慮將此情形變成的情況。
若,即可立刻得出答案。
否則,對於模方程,設
顯然,若,則此方程無解。
若方程有解,同時除以,得:
令,則方程變為:
遞迴計算,則答案為