BSGS算法!
Posted oierglh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BSGS算法!相关的知识,希望对你有一定的参考价值。
求解关于x的方程
a^x=z(mod p),其中gcd(a,p)=1.
做法的话并不难,但是要搞懂细节还蛮多的。
bsgs算法是这样的:x可以写成i*m-j的形式(这里m取值随意,但是取√p上取整时跑的最快)
a^(im-j)≡z(mod p)
推得 a^im≡z*(a^j)
那么我们枚举j的值从0--(m-1),将算出的z*(a^j)加入map里面
再枚举i从1-m,将每次算出的a^im的结果去map中匹配
若匹配到,x=i*m-j。
细节
1.i的范围从1到m
证明:
a ^ x Ξ b (mod p)
a ^ (p-1) Ξ 1 (mod p)
若x大于等于p-1
则a^xΞa^(p-1) * a^(x-p+1)Ξa^(x-p+1)
故x小于p-1
又m=√p
故i从1到m
得证
2.为什么bsgs在跳步过程中没有漏解
原因:在枚举i的过程中,看似是跳过了好多情况,但是其实在计算了每一个i之后,都会去map里面找每一个j去对应,相当于是将每一个i所对应的余数(剩余系)都枚举了一遍,即枚举了一遍完整的x的范围(因为x=i*m-j)。
洛谷p2485 计算器
bsgs裸题
直接粘代码
CODE!
#include<bits/stdc++.h> #define ll long long using namespace std; ll t,k,y,z,p; map<ll,ll>a; ll fpow(ll a,ll b,ll p) ll ret=1; while(b) if(b&1) ret=(ret*a)%p; b>>=1; a=(a*a)%p; return ret; void exgcd(ll a,ll b,ll &gcd,ll &xx,ll &yy) if(!b) xx=1,yy=0; gcd=a; return; exgcd(b,a%b,gcd,xx,yy); ll tr=xx; xx=yy; yy=tr-a/b*yy; int main() cin>>t>>k; if(k==1) while(t--) scanf("%lld%lld%lld",&y,&z,&p); printf("%lld\n",fpow(y,z,p)); else if(k==2) while(t--) scanf("%lld%lld%lld",&y,&z,&p); ll gcd,xx,yy; exgcd(y,p,gcd,xx,yy); if(z%gcd!=0) printf("Orz, I cannot find x!\n"); else xx*=z/gcd; xx%=(p/gcd); printf("%lld\n",(xx+(p/gcd))%(p/gcd)); else while(t--) scanf("%lld%lld%lld",&y,&z,&p); ll m=ceil(sqrt(p)); if(y%p==0&&z) printf("Orz, I cannot find x!\n");continue;; a.clear(); ll now=z%p,f=fpow(y,m,p); a[now]=0; for(ll i=1;i<=m;i++) now=(now*y)%p; a[now]=i; now=1; ll flag=0; for(ll i=1;i<=m;i++) now=(now*f)%p; if(a[now]) ll ans=(i*m-a[now])%p; printf("%lld\n",(ans+p)%p); flag=1; break; if(!flag) printf("Orz, I cannot find x!\n"); return 0;
ps.不开long long见祖宗可还行
以上是关于BSGS算法!的主要内容,如果未能解决你的问题,请参考以下文章