恶补数论 Baby-Step-Giant-Step 大步小步求离散模对数
Posted AronQi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了恶补数论 Baby-Step-Giant-Step 大步小步求离散模对数相关的知识,希望对你有一定的参考价值。
知识概述
好吧,我承认这是我初三寒假就听过的知识,然而我现在早就高一了(又是寒假,只不过我已经在省选了...)
额,这是求离散模对数的一种算法
也就是求满足方程a^x≡b(mod p)的最小的x(其中p为质数)
考虑将x分块?,根据欧拉定理,只需检查x=0,1,2...p-1是否是解即可,因为a^(p-1)≡1(mod p)当x超过p-1时就开始循环了哦
假设块的大小为m
先检查前m项,a^0,a^1,a^2...a^(m-1)是否满足要求,把ai mod p存在hash表ei里,求出a^m的逆a^(-m)
再考虑下面的m项,a^m,a^(m+1),a^(m+2),...,a^(2m-1),若存在解,则相当于存在i使ei*a^m≡b(mod n),两边左乘a^(-m)得ei≡b ‘ (mod n) (b ‘ =a^(-m)*b(mod p)).这样,只需检查是否存在ei=b ‘ 即可
模板
做个hash表吧
未测试模板1.0
//orz PoPoQQQ #include <math.h> #define dmin(a,b) ((a)<(b)?(a):(b)) int p;//p is a prime. struct Pep{ int first,second; Pep(int _=0,int __=0) : first(_),second(__) {} bool operator < (const Pep &other) const { return first < other.first; } } namespace Hash_Table{ #define inf ~0U>>1 #define MaxN 10010 struct Linker{ int hash,val; Linker *next; Linker(int _,Linker *__) : hash(_),val(inf),next(__) {} }*fir[MaxN]; inline int &Hash(int x){ int pos=x%MaxN; for(Linker *iter=fir[pos];iter;iter=iter->next) if(iter->hash==x) return iter->val; return (fir[pos]=new Linker(x,fir[pos]))->val; } } inline Pep exgcd(int a,int b){ if(!b)return Pep(1,0); Pep temp=exgcd(b,a%b); return Pep(temp.second,temp.first-x/y*temp.second); } inline int Baby_Step_Giant_Step(int A,int B){ int i,m=ceil(sqrt(p)),temp=1,D=1; for(i=0;i<=m;i++,(temp*=A)%=p){ int &val=Hash_Table::Hash(temp); val=dmin(val,i); D=temp; } for(temp=1,i=0;i<=m;i++,(temp*=D)%=p){ int x=((exgcd(temp,p).first%p)+p)%p; int &val=Hash_Table::Hash(x*B%p); if(val!=inf)return i*m+val; } return -1; }
以上是关于恶补数论 Baby-Step-Giant-Step 大步小步求离散模对数的主要内容,如果未能解决你的问题,请参考以下文章
BSGS(Baby-Step-Giant-Step)算法及其应用