zoukankan      html  css  js  c++  java
  • EXBSGS

    #include <bits/stdc++.h>
    #include <tr1/unordered_map>
    using namespace std;
    using std::tr1::unordered_map;
    #define ll long long
    const int maxn=1e6+7;
    const int mod=998244353;
    const int INF=0x3f3f3f3f;
    /*
       BSGS算法  b^l==n%p  求解最小的l
       不妨直接把l拆分成i*m-j,这样的话同余方程就变为b^(i*m)==n*b^j%p
       直接枚举j属于[0,m) m=ceil///向上取整(sqrt(p)) map记录当前的j的数值
       随后枚举i属于[0,m)查询map是否存在j满足且需要满足i*m>j=op[s]
       很显然这只是gcd(b,p)=1的情况,此时枚举只到了m-2与费马小定理对应
       EXBSGS 由于gcd(p,b)不一定为1,所以我们可以求出gcd(p,b)根据裴蜀定理,有解的条件gcd(p,b)|n
       所以就一直求出gcd(d2=(p/d),b),一直到他们之间互质,期间如果gcd(p/d,b)!|n就是无解
       最后可以得到b^cnt/(d1*d2......*dcnt) *b^(l-cnt) == n/(d1*d2......*dcnt)mod(p/(d1*d2......*dcnt))
       (d1*d2......*dcnt)=D
       b^cnt/D * (b^(l-cnt))===n/Dmod(p/D)
       b^cnt/D和n/d互质所以一定有解,所以将原来的S=1ll改为b^cnt/D直接用BSGS求(b^(l-cnt))
       求得的x是l-cnt最后要加上cnt
    */
    unordered_map<ll,ll>op;
    ll p,b,n;
    ll quick_pow(ll a,ll b,ll p)
    {
       ll ans=1;
       while (b)
       {
        if (b&1)///b为奇数
            ans=(ans*a)%p;
         a=(a*a)%p;///b为偶数
         b>>=1;
       }
       return ans;
    }
    ll BSGS(ll p,ll b,ll n,ll ans)
    {
        op.clear();
        ll m=ceil(sqrt(p));
        ll s=0;
        for (ll i=0,s=n;i<m;++i,s=s*1ll*b%p)///枚举的时候map记录位置
        {
            op[s]=i;
        }
        for (ll i=0,tmp=quick_pow(b,m,p),s=ans;i<m;++i,s=s*1ll*tmp%p )///查找j
        {
            if (op.find(s)!=op.end())
            {
                if (i*m>=op[s])return 1ll*i*m-op[s];
            }
        }
        return -1ll;
    }
    
    ll GCD(ll a,ll b){return b?GCD(b,a%b):a;}
    
    ll EXBSGS(ll p,ll b,ll n)
    {
        b%=p;
        n%=p;///先取模一下保证n,b<p
        if (n==1||p==1)return 0;///n==1 l==0 p==1 n%1==0  l任意取值,但要最小所以为0
        ll cnt=0;
        ll d=0;
        ll ans=1ll;
        while (d!=1)
        {
            d=GCD(b,p);
            if (n%d==1)return -1ll;///同余方程无解
            ++cnt;
            p/=d;
            n/=d;
            ans=(ans*1ll*b/d)%p;
            if (ans==n)return cnt;///特判情况 n*b^(l-cnt)==n/D mod(p/D) 此时的n*D==n%(p/d) 所以l==cnt
        }
        ll ret=BSGS(p,b,n,ans);
        if (ret==-1ll)return -1ll;
        else return ret+cnt;///求的是a^(x-cnt)
    }
    
    int main()
    {
        while (EOF!=scanf("%lld%lld%lld",&b,&p,&n))///b^l==n%p
        {
            if (!b&&!p&&!n)return 0;
            ll cnt=EXBSGS(p,b,n);
            cnt==-1ll?cout<<"No Solution"<<endl:cout<<cnt<<endl;
        }
        return 0;
    }
    

    摘录自对该博客的理解

    齐芒行,川锋明!
  • 相关阅读:
    Lc5413_重新排列句子中的单词
    Lc5412._在既定时间做作业的学生人数
    Lc520_检测大写字母
    threadPoolExecutor的参数和拒绝策略
    coutdownlatch的使用
    volatile的个人理解
    Lc292_Nim 游戏
    Lc136_只出现一次的数字
    lc88_合并两个有序数组
    jdk源码_String(1)
  • 原文地址:https://www.cnblogs.com/qimang-311/p/13408448.html
Copyright © 2011-2022 走看看