通常用來求\(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快這麼多啊,不過有時候編譯會出鍋...