「SPOJ 3105」Power Modulo Inverted

「SPOJ 3105」Power Modulo Inverted

传送门

题目大意:

求关于 \(x\) 的方程
\[ a^x \equiv b \;(\mathrm{mod}\; p) \]
的最小自然数解,不保证 \(a,p\) 互质


如果保证 \(a,p\) 互质,那么可以直接使用 \(\texttt{BSGS}\) 算法通过本题。

对于这道题目,我们考虑将式子变形

\(t=\gcd(a,p)\),则有
\[ \frac{a}{t}a^{x-1} \equiv \frac{b}{t} \;(\mathrm{mod} \; \frac{p}{t}) \]
得到
\[ \frac{a}{t} \cdot a^{x-1} \equiv b^{'} \;(\mathrm{mod} \; p^{'}) \]
(可以将其转换为等式,可能更好理解)

显然,当 \(b \; \mathrm{mod} \;t =0\) 时可能有解,我们只需要按照这种方式已知递归求解,直至 \(a^{'},p^{'}\) 互质即可。

另外特别需要注意的是,最小自然数解可能在迭代时就已求出,所以在迭代时需要进行特判。

每一次有效的操作至少会将 \(p\) 除以 \(2\) ,求解 \(\gcd\) 的复杂度为 \(O(log_2n)\),故这样迭代的总复杂度为 \(O(log_2^2n)\)

然后就可以求解了!

贴代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
ll ksm(ll a,ll b,ll p){
    ll ans=1;
    for(;b;b>>=1,a=1ll*a*a%p)
        if(b&1) ans=1ll*ans*a%p;
    return ans;
}
ll gcd(ll a,ll b){
    if(!b) return a;
    return gcd(b,a%b);
}
ll bsgs(ll a,ll b,ll p){
    unordered_map<int,int> mp;
    ll tim=0,A=1;
    while(1){
        ll t=gcd(a,p);if(t==1) break;
        if(b%t) return -1;
        b/=t,p/=t,A=1ll*A*(a/t)%p;
        ++tim;
        if(b==A) {
            return tim;
        }
    }
    ll m=sqrt(p)+1;
    ll tmp=b;
    for(ll i=0;i<m;++i,tmp=1ll*tmp*a%p) mp[tmp]=i;
    tmp=ksm(a,m,p);
    ll now=1ll*A*tmp%p;
    for(ll i=1;i<=m;++i,now=1ll*now*tmp%p){
        if(mp[now]){
            if(i*m-mp[now]+tim>=0) return i*m-mp[now]+tim;
        }
    }
    return -1;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    ll x,y,z;
    while(cin>>x>>y>>z&&(x||y||z)){
        
        ll tmp=bsgs(x,z,y);
        if(tmp==-1) cout<<"No Solution"<<'\n';
        else cout<<tmp<<'\n'; 
    }   
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/HenryHuang-Never-Settle/p/SPOJ3105.html