1. 程式人生 > >bsgs(大步小步演算法)和exbsgs(擴充套件大步小步演算法)學習小記

bsgs(大步小步演算法)和exbsgs(擴充套件大步小步演算法)學習小記

翻譯:

bsgs:
baby steps,giant steps

bsgs:

解決以下問題:
有三個整數a,b,p,其中p是質數。

求最小的自然數x,使ax=b(modp)

根據費馬小定理,ap1=1(modp),所以只用考慮x=0~p-1

m=p,則x可以表示成im+j(0<=i,j<m)

ax=b(modp)
aim+j=b(modp)
baj=aim(modp)

於是容易想到列舉

j,用個hash表存一下baj

接著列舉i,判斷hash表裡有沒有aim就行了。

裸題:
【SDOI2011】計算器

Code不放了,與exbsgs類似。

exbsgs:

p不是質數。

ax=b(modp)

d=gcd(a,p)

此時如果b不是d的倍數且b≠1,無解,如果b=1,x=0。

可以改寫成:
ax1ad=bd(modpd)

此時a可能與pd還不互質,那就一直取gcd,設取了k次,則最後式子是:
axk

akdi=bdi(modpdi)

此時互質了,直接套用bsgs,答案加個k就行了。

但是要注意一下x<k的情況,這個在之前的試除就可以判掉。

Code(【SDOI2011】計算器):

裸題:
SPOJ MOD

Code:

#include<cstdio>
#include<cmath>
#include<map>
#define ll long long 
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
using namespace std;

ll a, b, p;

ll ksm(ll x, ll y, const
ll mo) { ll s = 1; for(; y; y /= 2, x = x * x % mo) if(y & 1) s = s * x % mo; return s; } ll gcd(ll x ,ll y) { return !y ? x : gcd(y, x % y); } map<ll, ll> h; ll exbsgs(ll a, ll b, ll p) { if(b == 1) return 0; ll k = 0, d = 1, t; while((t = gcd(a, p)) != 1) { if(b % t) return -1; k ++, b /= t, p /= t, d = d * (a / t) % p; if(b == d) return k; } h.clear(); ll m = sqrt(p * 1.0), a_m = ksm(a, m, p); ll mul = b; fo(j, 1, m) { mul = mul * a % p; h[mul] = j; } fo(i, 1, m) { d = d * a_m % p; if(h[d]) return i * m - h[d] + k; } return -1; } int main() { while(1) { scanf("%lld %lld %lld", &a, &p, &b); if(a == 0 && b == 0 && p == 0) return 0; ll ans = exbsgs(a, b, p); if(ans == -1) printf("No Solution\n"); else printf("%lld\n", ans); } }