• [日常摸鱼]poj2417 DiscreteLoggingBSGS算法


    在这题TLE了一天…T_T

    BSGS裸题…不知道为什么一直挂

    第二天(也就是今天)换成黄学长博客里的写法就过掉了


    题意:解关于$x$的方程:$a^x \equiv b \pmod{p}$,$p$为质数,有多解则输出最小的那个

    (和原题里的字母不一样x)

    这玩意好像叫离散对数。

    首先得注意到$x$的取值只有可能是$0~p-1$,因为费马小定理告诉我们$a^{p-1} \equiv a^{0} \pmod{p}$,这时候出现了循环

    不过直接枚举复杂度还是不行的

    考虑把$x$写成$x=k*m+i$的形式(这里先不说$m$取多少),原方程变成$a^{km+i} \equiv b \pmod{p}$

    移过去:$a^i \equiv b*a^{-km} \pmod{p}$

    然后可以先处理出所有可能的$i$(即$i=0,1,...,m-1$)所对应的$a^i$,然后把每个结果和对应的最小的$i$存到map里面

    再枚举$k$,根据需要的结果查找所对应的的最小$i$,这里计算$a^{-km}$可以递推

    根据费马小定理$1 \equiv a^{p-1} \pmod{p}$两边乘上$a^{-m}$就可以得到$a^{-m} \equiv a^{p-1-m} \pmod{p}$

    然后我们可以根据$k$来递推$a^{-km}$

    然后来看看怎么取$m$,预处理所有的$a^i$一共是$m$个,丢到map里复杂度也是就是$O(mlogm)$

    对于给定的$m$,要枚举$\frac{p}{m}$个$k$,每次也是log的复杂度,总复杂度$O((m+\frac{p}{m})log m)$

    所以当$m$取$\sqrt{p}$时复杂度最优,复杂度$O(\sqrt{p}log \sqrt{p})$

    实现的地方把map[1]=0写成map[1]=m+1(一个取不到的值)应该也是为了方便后面的判断

    #include<cstdio>
    #include<cmath>
    #include<map>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    typedef long long lint;
    
    map<lint,lint>x;
    
    inline lint mul_mod(lint a,lint b,lint p)
    {
        lint res=a%p*b%p;res=(res%p+p)%p;return res;
    }
    
    inline lint pow_mod(lint a,lint b,lint p)
    {
        lint res=1;
        for(;b;b>>=1,a=(a*a)%p)if(b&1)res=(res*a)%p;
        return res;
    }
    
    inline lint BSGS(lint a,lint b,lint p)
    {
        a%=p;x.clear();
        if(!a&&!b)return 1;
        if(!a)return -1;
        lint m=ceil(sqrt(p)),t=1;
        x[1]=m+1;
        for(register int i=1;i<m;i++)
        {
            t=mul_mod(t,a,p);
            if(!x[t])x[t]=i;
        }
        lint tmp=pow_mod(a,p-m-1,p),inv=1;
        for(register int k=0;k<m;k++)
        {
            lint i=x[b*inv%p];
            if(i)
            {
                if(i==m+1)i=0;
                return k*m+i;
            }
            inv=mul_mod(inv,tmp,p);
        }
        return -1;
    }
    
    int main()
    {
        //freopen("input.in","r",stdin);
        lint res,b,n,p;
        while(scanf("%lld%lld%lld",&p,&b,&n)==3)
        {
            res=BSGS(b,n,p);
            if(res==-1)puts("no solution");
            else printf("%lld\n",(res%p+p)%p);
        }
        return 0;
    }
    View Code

    如果有说错还请在评论区怼我

  • 相关阅读:
    WPF如何判断PNG中的点是透明的
    Silverlight DataGrid自适应数据
    DEVExpress For WPF 中GridControl如何实现滚动分页(延迟查询)
    如何通过样式来处理根据自身其他属性内容赋值其他属性值的方法研究
    最近涉及到的一些需要备忘的东西
    (转载)Setup Factory 会话变量
    (转载)解决WPF动画属性锁死问题
    WPF InkCanvas MouseDown及MouseLeftButtonDown事件不触发的代替事件
    在win7与XP系统下 C#缺省路径不同
    Xamarin笔记
  • 原文地址:https://www.cnblogs.com/yoshinow2001/p/7979008.html
Copyright © 2020-2023  润新知