P4195 【模板】exBSGS/Spoj3105 Mod

传送门

首先要懂得 $BSGS$,$BSGS$ 可以求出关于 $Y$ 的方程 $X^Y \equiv Z (mod\ mo)$ 的最小解,其中 $gcd(X,Z)=1$

$exBSGS$ 算是 $BSGS$ 的进一步扩展,使得当 $gcd(X,Z)!=1$ 时仍然适用

先把方程转换成 $X^Y+k*mo=Z$ 的形式

因为 $Y,k$ 都是整数,所以 $Z$ 必须是 $gcd(X,mo)$ 的倍数,不然无解

所以可以把方程左右同除 $gcd(X,mo)$,变成 $X^{(Y-1)}*\frac{X}{gcd(X,mo)}+k*\frac{mo}{gcd(X,mo)}=\frac{Z}{gcd(X,mo)}$

其实这个方程就相当于 $\frac{X}{gcd(X,mo)}*X^{(Y-1)} \equiv \frac{Z}{gcd(X,mo)} (mod\ \frac{mo}{gcd(X,mo)})$

发现 $\frac{X}{gcd(X,mo)}$ 只是一个系数,如果此时 $gcd(X,\frac{mo}{gcd(X,mo)})=1$ 则可以直接套用 $BSGS$ 求解

如果此时 $gcd(X,\frac{mo}{gcd(X,mo)})!=1$ 则可以继续上述操作直到 $gcd$ 为 $1$

设第 $i$ 次操作的 $gcd$ 为 $d_i$,总共进行了 $T$ 次操作

则最后式子的形式为 $\frac{X^T}{\prod _{i=1}^{T}d_i}X^{Y-T} \equiv \frac{Z}{\prod _{i=1}^{T}d_i}\ \ (mod\ \frac{mo}{\prod _{i=1}^{T}d_i})$

要记得特判 $Y \in [0,T]$ 的情况

具体看代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ldb;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
int gcd(int a,int b) { return b ? gcd(b,a%b) : a; }
map <int,int> mp;
inline int ksm(int x,int y,int mo)
{
    int res=1;
    while(y)
    {
        if(y&1) res=1ll*res*x%mo;
        x=1ll*x*x%mo; y>>=1;
    }
    return res;
}
// X^Y=Z (mod mo)
void exBSGS(int X,int Z,int mo)
{
    if(Z==1) { printf("0\n"); return; }
    int d=gcd(X,mo),t=0,k=1;
    while(d!=1)
    {
        if(Z%d) { printf("No Solution\n"); return; }
        t++; k=(1ll*k*(X/d))%mo; mo/=d; Z/=d;
        if(k==Z) { printf("%d\n",t); return; }
        d=gcd(X,mo);
    }
    int m=sqrt(mo)+1; mp.clear();
    for(int b=0,s=Z; b<m; b++,s=1ll*s*X%mo) mp[s]=b;
    for(int a=1,p=ksm(X,m,mo),s=1ll*k*p%mo; a<=m+1; a++,s=1ll*s*p%mo)
    {
        if(mp.find(s)==mp.end()) continue;
        printf("%d\n",a*m-mp[s]+t); return;
    }
    printf("No Solution\n");
}
int main()
{
    int X=read(),mo=read(),Z=read();
    while(X||Z||mo)
    {
        exBSGS(X,Z,mo);
        X=read(),mo=read(),Z=read();
    }
    return 0;
}

 

posted @ 2019-07-31 20:41  LLTYYC  阅读(243)  评论(0编辑  收藏  举报