BSGS(大小步)算法
BSGS算法主要用于求解形如ax≡b(mod p)的式子中x的值。
在这里我们不妨设
x=k1*n-k2
这时我们就可以将式子转化为
ak1*n≡b*ak2(mod p)
这里的n我们设为√p,所以我们利用分块的思想在块数范围内枚举k1即可。那在考虑完k1和n之后我们再考虑一下如何找到k2,我们建立一个哈希表,将k2取0~n时的式子左边的值模p然后将其映射到此时k2的取值。求最后答案时我们只需找到在k1最小时满足条件的最大的k2即可。
更新
发现以前有点问题
根据欧拉定理$a^{\varphi(p)} \equiv 1(mod p)$
所以代码里所有的$p$都替换成$\varphi(p)$即可
块的大小也为$\sqrt{\varphi(p)}$
模板(poj2417)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
map<long long,long long>mp;
inline long long pw(long long a,long long p,long long mod){
long long res=1;
while(p){
if(p&1)res=res*a%mod;
a=a*a%mod;
p>>=1;
}
return res;
}
int main(){
long long a,b,p,m,n,i,j,k,pl;
while(scanf("%lld%lld%lld",&p,&a,&b)!=EOF){
n=ceil(sqrt(p));
mp.clear();
long long x=b%p;
mp[x]=0;
for(i=1;i<=n;i++){
x=x*a%p;
mp[x]=i;
}
long long y=pw(a,n,p),ok=0;
x=1;
for(i=1;i<=n;i++){
x=x*y%p;
if(mp[x]){
ok=1;
pl=i;
break;
}
}
if(ok){
printf("%lld\n",((pl*n%p-mp[x])%p+p)%p);
}else puts("no solution");
}
return 0;
}