通常用来求\(a^x\equiv b\,\,(mod\,p)\)的最小正整数解,其中gcd(a,p)=1c++
设\(u=\lceil sqrt(p)\rceil\),则式子能够转化为\(a^{iu-j}\equiv b\,\,(mod\,p)\),其中\(i\in[1,u],j\in[0,u)\)git
因而\(a^{iu}\equiv a^jb\,\,(mod\,p)\),咱们就能够枚举j,存到map中,再枚举i判重就好了ui
不过当存在不一样的j使\(a^jb\,mod\,p\)相同时,咱们记录较大的(由于j越大答案越小嘛)spa
费马小定理:若gcd(x,p)=1,则有\(\\x^{p-1}\equiv1\,\,(mod\,p)\),获得\(x^p\equiv x\,\,(mod\,p)\)code
因此当指数不小于p时,mod p的值会造成循环get
板子题:luogu P4028 New Productit
#include<bits/stdc++.h> #define ll long long using namespace std; map<int,int> mp; int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } int quickpow(int a,int b,int p){ int re=1; while(b){if(b&1) re=1ll*re*a%p;a=1ll*a*a%p;b>>=1;} return re; } void solve(){ int p=read(),a=read(),b=read(); if(a%p==0){puts("Couldn't Produce!");return ;} if(b==1){puts("0");return ;} int u=sqrt(p)+1,v=b;mp.clear(); for(int i=0;i<u;i++) mp[v]=i,v=1ll*v*a%p; int w=quickpow(a,u,p);v=1; for(int i=1;i<=u;i++){v=1ll*v*w%p; if(mp.count(v)){ printf("%d\n",i*u-mp[v]); return ; } }puts("Couldn't Produce!"); } int main(){ int T=read(); while(T--) solve(); return 0; }
能够看到BSGS是有着局限性的,即必须知足gcd(a,p)=1io
那么当gcd(a,p)!=1时呢?咱们设\(d=gcd(a,p)\)编译
咱们首先判断\(b\)是否知足\(d|b\),若不知足,由裴蜀定理可知无解class
式子转化为:
\[ a^{x-k}\frac{a^k}{\Pi_{i=1}^kd_i}\equiv \frac{b}{\Pi_{i=1}^kd_i}\,\,(mod\,\,\frac{p}{\Pi_{i=1}^kd_i}) \]
令\(c=\frac{a^k}{\Pi_{i=1}^kd_i},b'=\frac{b}{\Pi_{i=1}^kd_i},p‘=\frac{p}{\Pi_{i=1}^kd_i}\),若\(c=b'\),则直接输出\(k\)
令\(d=gcd(a,p')\),若\(d\ne 1\),则返回step1,不过b变成了b'
所有完成后,咱们获得式子:\(a^{x-k}c\equiv b'\,\,(mod\,\,p')\),此时知足\(gcd(a,p')=1\)
那么咱们即可以直接BSGS了
#include<bits/stdc++.h> #include<unordered_map> #define ll long long using namespace std; unordered_map<int,int> mp; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } inline int gcd(int x,int y){ if(y>x) swap(x,y); while(y){swap(x,y);y=y%x;} return x; } inline int quickpow(int a,int b,int p){ int re=1; while(b){if(b&1) re=1ll*re*a%p;a=1ll*a*a%p;b>>=1;} return re; } inline void solve(int a,int p,int b){ if(p==1){puts("0");return ;} if(b==1){puts("0");return ;} int d=gcd(a,p),flag=0,k=0,c=1; while(d^1){ if(b%d){ puts("No Solution"); flag=1;break; }p/=d,b/=d,++k; c=1ll*c*(a/d)%p; if(b==c){ printf("%d\n",k); flag=1;break; }d=gcd(a,p); }if(flag) return ; mp.clear(); int u=sqrt(p)+1,v=b; for(int i=0;i<u;i++) mp[v]=i,v=1ll*v*a%p; v=c,c=quickpow(a,u,p); for(int i=1;i<=u;i++){ v=1ll*v*c%p; if(mp.count(v)){ printf("%d\n",i*u-mp[v]+k); return ; } }puts("No Solution"); } int main(){ while(1){ int a=read(),p=read(),b=read(); if(a==0&&b==0&&p==0) return 0; a%=p;b%=p;solve(a,p,b); } }
话说为何unordered_map比map快这么多啊,不过有时候编译会出锅...