拔山盖世学习笔记

咕了这么久,也该补上了……

拔山盖世×扩展拔山盖世敬上:

$A^x\equiv B\pmod{C}$

上面这个就是北上广深的应用,一般的北上广深只能应用于$C$为质数的时候,扩展应用于$C$为任何数时。

先来看一般的类型:

由费马小定理可知:若$A$不是$C$的倍数,则有:$A^{C-1}\equiv1\pmod{C}$。还有显然的$A^0\equiv1\pmod{C}$

所以我们的暴力只需要跑$O_{(C)}$即可。

考虑一个神仙的优化:我们可以设$m=ceil(\sqrt{C})$,则一定有:$x=i*m-j$

令$j\in(0,m)$ ,则原式可变为:$A^{i*m}\equiv B*A^j\pmod{C}$

所以我们可以先与处理出$A^j$然后枚举$i$即可复杂度为:$O_{(m)}$

(先不放代码ヾ(o◕∀◕)ノヾ)

再来看一下扩展拔山盖世:

引理:如果有$d\mid A$且$d\mid B$且$d\mid C$,则有:$A^{x-1}*\frac{A}{d}\equiv \frac{B}{d}\pmod{\frac {C}{d}}$

那么这样下去,我们可以每次令$d=\gcd(A,{mod后面的数})$直到$d=1$为止。

然后再跑拔山盖世就行啦,正式上代码:

//A^x≡B(mod C)
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
map<int,int> mp;
inline int gcd(int a,int b){return !b?a:gcd(b,a%b);}
inline int EXBSGS(int A,int B,int C)
{
    if(B==1) return 0;
    int d,cnt=0,k=1;
    while((d=gcd(A,C))^1)
    {
        if(B%d) return -1;
        B/=d;C/=d;++cnt;
        k=(k%C*(A/d)%C)%C;
        if(k==B) return cnt;
    }
    mp.clear();
    int m=sqrt(C)+1,now=1;
    for(int i=0;i<m;i++)
    {
        mp[(now*B)%C]=i;
        now=((now%C)*(A%C))%C;
    }
    k=((k%C)*(now%C))%C;
    for(int i=1;i<=m;i++)
    {
        if(mp[k]) return ((i%C)*(m%C)-mp[k]+cnt+C)%C;
        k=((k%C)*(now%C))%C;
    }
    return -1;
}
main(){
    int A,B,C;
    scanf("%lld%lld%lld",&A,&C,&B);
    while(A&&B&&C)
    {
        int ans=EXBSGS(A,B,C);
        if(ans==-1) printf("No Solution\n");
        else printf("%lld\n",ans);
        scanf("%lld%lld%lld",&A,&C,&B);
    }
}

 

posted @ 2019-04-02 17:47  风骨傲天  阅读(163)  评论(0编辑  收藏  举报