BSGS
BSGS可以用于解决一类离散对数问题,一般形如
Ax≡B(modC)
其中C为质数
它是怎么做的?
我们令m=⌈C⌉,那么x=im+j,i∈[0,m−1],j∈[0,m−1]
于是原方程转化为
Aim×Aj≡B(modC)
即
Aj≡B×A−im(modC)
我们知道gcd(A,C)=1,所以A在模C意义下存在逆元,Ak也是
那么我们将所有的Aj存进哈希表里(Baby Step),然后枚举i(Giant Step),如果找到一个i满足上式,那么我们就找到了一个解x=i×m+j
如果i在[0,m−1]内没有解,那么原方程无解
因为根据欧拉定理,Aφ(C)=AC−1≡1(modC),AC≡A(modC),出现循环节
所以原方程如果有解,最小的解一定在[0,C−1]范围内,否则无解
时间复杂度O(C)
但是我太菜了,不会写哈希表,只会用map,时间复杂度到了O(ClogC),才能勉强维持一下生活这样子
BSGS是一种典型的空间换时间的思想
例题
「Luogu3846」[TJOI2007]可爱的质数
板题,直接上BSGS就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #include <iostream> #include <map> #define mp(x,y) (make_pair((x),(y))) #define inv(x) (fastpow((x),c-2)) using namespace std; typedef long long ll; typedef pair<ll,ll> pll;
template <typename T>void read(T &t) { t=0;int f=0;char c=getchar(); while(!isdigit(c)){f|=c=='-';c=getchar();} while(isdigit(c)){t=t*10+c-'0';c=getchar();} if(f)t=-t; }
ll a,b,c; ll m; map<ll,ll> rec;
ll fastpow(ll a,ll b) { ll re=1,base=a; while(b) { if(b&1) re=re*base%c; base=base*base%c; b>>=1; } return re; } int main() { read(c),read(a),read(b); rec.clear(); m=ceil(sqrt(c)); for(register ll i=0,po=1;i<m;++i,po=po*a%c) rec.insert(mp(po,i)); ll iam=inv(fastpow(a,m)); for(register ll i=0,tmp=1;i<m;++i,tmp=tmp*iam%c) if(rec.find(b*tmp%c)!=rec.end()) { printf("%lld\n",m*i+rec[b*tmp%c]); return; } printf("no solution\n"); return 0; }
|