所谓 BSGS,就是北上广深。
(逃)
BSGS
给出 a,b,pa,b,pa,b,p,请处出满足 ax≡b(modp)a^x\equiv b\pmod pax≡b(modp) 的最小非负正数解或者报告无解。
a,b,p≤109,gcd(a,p)=1a,b,p\le 10^9,\gcd(a,p)=1a,b,p≤109,gcd(a,p)=1
由于 a,pa,pa,p 互质,有 aφ(p)≡1(modp)a^{\varphi(p)}\equiv 1\pmod paφ(p)≡1(modp),所以答案如果存在,不会超过 O(p)O(p)O(p) 级别。
设 w=⌈p⌉w=\lceil \sqrt{p} \rceilw=⌈p⌉,xxx 可以拆分为 xw−y(x,y≤p)xw-y \pod {x,y\le \sqrt p}xw−y(x,y≤p)。
变一下型:
axw−y≡b(modp)a^{xw-y}\equiv b\pmod paxw−y≡b(modp)
axw≡b⋅ay(modp)a^{xw}\equiv b\cdot a^y\pmod paxw≡b⋅ay(modp)
先枚举右边存到 map
或者哈希表里,然后左边暴力查表即可。
ll bsgs(ll a,ll b,ll mod){if(b==0&&a==0) return 1;if(b==1) return 0;if(a==0||b==0) return -1;mp.clear();ll w=ceil(sqrt(mod)),ans=1e16;for(ll i=0,now=1;i<=w;i++,now=now*a%mod){int x=b*now%mod;mp.ins(x,i);}ll bas=ksm(a,w,mod);for(ll i=1,now=bas;i<=w;i++,now=now*bas%mod){int o=mp.find(now);if(o!=-1) ans=min(ans,i*w-o);}return ans>1e15?-1e9:ans;
}
exBSGS
给出 a,b,pa,b,pa,b,p,请处出满足 ax≡b(modp)a^x\equiv b\pmod pax≡b(modp) 的最小非负正数解或者报告无解。
a,b,p≤109a,b,p\le 10^9a,b,p≤109
没有 a,pa,pa,p 互质的条件,之前的算法行不通了。
因此我们要试图转化为互质的情况。
一个朴素的想法是同时除以 gcd\gcdgcd。
但是我们如果改变了 aaa,后面会很难搞。
有一个性质,如果有:
a≡b(modp)a\equiv b\pmod pa≡b(modp)
那么对于 a,b,pa,b,pa,b,p 的公因数 ggg,有:
ag≡bg(modpg)\frac{a}{g}\equiv \frac{b}{g}\pmod {\frac{p}{g}}ga≡gb(modgp)
带回方程:
ax−1⋅ag≡bg(modpg)a^{x-1}\cdot\frac{a}{g}\equiv \frac{b}{g}\pmod {\frac{p}{g}}ax−1⋅ga≡gb(modgp)
ax−1≡bg⋅ag(modpg)a^{x-1}\equiv \frac{b}{g\cdot\frac{a}{g}}\pmod {\frac{p}{g}}ax−1≡g⋅gab(modgp)
就对方程完成了转化。
但是,这样只是对 ppp 除 ggg 后,依然有可能 p,ap,ap,a 不互质。
那么我们就找到新的 ggg,直到互质为止。
假设除了 kkk 次,就有:
ax−k≡b(∏kgk)⋅∏kagka^{x-k}\equiv \frac{b}{(\prod_kg_k)\cdot\prod_k\frac{a}{g_k}}ax−k≡(∏kgk)⋅∏kgkab
右边的分母在实现时是分开除的,所以这里也不化简了)
但是我们需要注意一些细节问题。
- 如果 gcd(a,p)\gcd(a,p)gcd(a,p) 不是 bbb 的因子怎么办?
如果 a,pa,pa,p 是 ggg 的倍数,那么 axmodpa^x\bmod paxmodp 必然也是 ggg 的倍数(可以把取模理解成减倍数来考虑),那么既然无解。(除非 b=1 !)
- ppp 不是质数,如何求 ∏kagk\prod_k\frac{a}{g_k}∏kgka 的逆元?
如果 a,pa,pa,p 互质,那么 ∏kagk\prod_k\frac{a}{g_k}∏kgka (也就是 aaa 的一堆因子乘起来)必然也与 ppp 互质,用 exgcd\mathrm{exgcd}exgcd 求解即可。
代码
inline ll ksm(ll x,ll k,ll mod){//快速幂ll res(1);while(k){if(k&1) res=1ll*x*res%mod;x=1ll*x*x%mod;k>>=1;}return res;
}
struct node{int to,nxt;
};
struct Hash{//哈希表int mod,key[N],val[N],tot,cnt;bool vis[N]; vector<int> exi;int fi[N];node p[N];inline void init(int x){mod=x;memset(fi,-1,sizeof(fi));cnt=-1;}void ins(int k,int w){int o=k%mod;if(!vis[o]){vis[o]=1;exi.push_back(o);}for(int i=fi[o];~i;i=p[i].nxt){int to=p[i].to;if(key[to]==k){val[to]=w;return;}}++tot;val[tot]=w;key[tot]=k;p[++cnt]=(node){tot,fi[o]};fi[o]=cnt;}int find(int k){int o=k%mod;for(int i=fi[o];~i;i=p[i].nxt){int to=p[i].to;if(key[to]==k) return val[to];} return -1;}void clear(){for(int x:exi){fi[x]=-1;vis[x]=0;}tot=0;cnt=-1;exi.clear();return;}
}mp;
ll bsgs(ll a,ll b,ll mod){if(b==0&&a==0) return 1;if(b==1) return 0;if(a==0||b==0) return -1;mp.clear();ll w=ceil(sqrt(mod)),ans=1e16;for(ll i=0,now=1;i<=w;i++,now=now*a%mod){int x=b*now%mod;mp.ins(x,i);}ll bas=ksm(a,w,mod);for(ll i=1,now=bas;i<=w;i++,now=now*bas%mod){int o=mp.find(now);if(o!=-1) ans=min(ans,i*w-o);}return ans>1e15?-1e9:ans;
}
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}//gcd
ll exgcd(ll x,ll y,ll &a,ll &b){//exgcdif(!y){a=1;b=0;return x;}ll g=exgcd(y,x%y,a,b),tmp=a;a=b;b=tmp-x/y*b;return g;
}
ll inv(ll x,ll mod){//x的逆元ll a,b;ll g=exgcd(x,mod,a,b);assert(g==1);a=(a%mod+mod)%mod;return a;
}
ll a,b,w;
ll ans=1e18;
ll exbsgs(ll a,ll b,ll mod){//exbsgsif(b==1||mod==1) return 0;ll k(0),g=gcd(a,mod),na=1;while(g>1){++k; if(b%g) return -1;b/=g;mod/=g;na=na*a/g%mod;g=gcd(mod,a);if(b==na) return k;//此时b变成了1}return bsgs(a,b*inv(na,mod)%mod,mod)+k;
}