拔山盖世学习笔记

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

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

$A^xequiv Bpmod{C}$

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

先来看一般的类型:

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

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

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

令$jin(0,m)$ ,则原式可变为:$A^{i*m}equiv B*A^jpmod{C}$

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

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

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

引理:如果有$dmid A$且$dmid B$且$dmid 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
");
        else printf("%lld
",ans);
        scanf("%lld%lld%lld",&A,&C,&B);
    }
}
原文地址:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/10644168.html