• x^a=b(mod c)求解x在[0,c-1]上解的个数模板+原根求法


    /*************************************
     求解x^a=b(mod c) x在[0,c-1]上解的个数模板
     输入:1e9>=a,b>=1,1e9>=c>=3.
     返回:调用xaeqbmodc(a,b,c),返回解的个数
     复杂度: 找原根的复杂度很低,所以总的复杂度为O(c^0.5)
     ************************************/
    
    typedef long long ll;
    #define HASH_N 100007
    
    struct hashnode
    {
        int next;
        ll key;
        int j;
    }HashLink[ HASH_N ];
    
    int hashpre[ HASH_N ],hashcnt;
    
    void hash_insert(ll x,ll key,int j)
    {
        for(int p=hashpre[x];p!=-1;p=HashLink[p].next)
        {
            if(HashLink[p].key==key) return ;
        }
        HashLink[ hashcnt ].key = key;
        HashLink[ hashcnt ].j = j;
        HashLink[ hashcnt ].next = hashpre[x];
        hashpre[x] = hashcnt++;
    }
    
    int hash_get(ll key)
    {
        ll x=key%HASH_N;
        for(int p=hashpre[x];p!=-1;p=HashLink[p].next)
        {
            if( HashLink[p].key == key ) return HashLink[p].j;
        }
        return -1;
    }
    
    ll gcd(ll a,ll b)
    {
        if(b==0) return a;
        return gcd(b,a%b);
    }
    
    //ax + by = gcd(a,b)
    //传入固定值a,b.放回 d=gcd(a,b), x , y
    void extendgcd(long long a,long long b,long long &d,long long &x,long long &y)
    {
        if(b==0){d=a;x=1;y=0;return;}
        extendgcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
    
    //Ax=1(mod M)
    //返回x的范围是[0,M-1]
    ll GetNi(ll A,ll M)
    {
        ll rex=0,rey=0;
        ll td=0;
        extendgcd(A,M,td,rex,rey);
        return (rex%M+M)%M;
    }
    
    //a^b%mod 快速幂
    long long Quk_Mul(long long a,long long b,long long mod)
    {
        long long qsum=1;
        while(b)
        {
            if(b&1) qsum=(qsum*a)%mod;
            b>>=1;
            a=(a*a)%mod;
        }
        return qsum;
    }
    
    //测试x较小的情况,必须!
    ll firsttest(ll A,ll B,ll C)
    {
        ll tmp=1;
        if(B==1) return 0;
        for(int i=1;i<100;i++)
        {
            tmp = (tmp*A)%C;
            if(tmp==B) return i;
        }
        return -1;
    }
    
    ll BabyStep(ll A,ll B,ll C,ll OC)
    {
        if(0==A || 0==C) return -1;
        if(C==1) return 0;
        B = B%C;
        ll ans = firsttest(A,B,C);//为了防止x比较小的时候
        if(ans != -1) return ans;
        ll D=1;
        int c=0;
        ll d;
        while( (d=gcd(A,C)) != 1 )
        {
            if( B%d !=0 ) return -1;//无解的情况
            B /= d;
            C /= d;
            D = D*A/d%C;
            c++;
        }
        
        //得到了 D*A^(x-c)=B (mod C) ,gcd(A,C)=1 , gcd(D,C)=1
        ll D_1=GetNi(D,C);//求D的逆元
        B = B*D_1%C;
        //求A^x=B (mod C),然后返回x+c
        ll m = ceil( sqrt(C+0.0) );
        
        memset(hashpre,-1,sizeof(hashpre));
        hashcnt=0;
        ll hashnum=1;
        hash_insert(1, 1, 0);
        for(int i=1;i<m;i++)
        {
            hashnum = (hashnum*A)%C;
            hash_insert(hashnum%HASH_N, hashnum ,i);
        }
        
        ll ol=OC;//这一步可以省略
        ll mA=Quk_Mul(A, m, C);
        ll ta=1;
        
        ll tmpni = Quk_Mul(mA, ol-1, C);
        
        for(int i=0;i<m;i++,ta=ta*tmpni%C)
        {
            //解线性同余方程 tx=B*ta (%C) ,ta直接用费马小定理求逆元
            ll tx = ta;
            tx = (tx*B)%C;
            int j=hash_get(tx);
            if(j!=-1)//找到解了
            {
                return i*m+j+c;
            }
        }
        
        return -1;
    }
    
    ll mypow(ll a,ll b)
    {
        ll sum=1;
        for(int i=1;i<=b;i++)
            sum*=a;
        return sum;
    }
    
    ll slove(ll a,ll b,ll c,ll p,int a1)
    {
        //第0种情况a==1
        if(a==1) return 1;
        
        //第一种情况b==c
        b %= c;
        if(b==0)
        {
            ll tmp = mypow(p,ceil( (double)a1/a ) );
            return c/tmp;
        }
        ll d=gcd(b,c);
        //第二种情况 gcd(b,c)!=1
        if( d != 1 )
        {
            return 0;
        }
        
        //第三种情况 gcd(b,c)==1
        
        //第一步找出原根x0,
        ll save[55];
        int cnt=0;
        
        ll tc = mypow(p,a1-1)*(p-1);
        for(ll i=2;i*i<=tc;i++)
        {
            if(tc%i == 0)
            {
                save[ cnt++ ] = i;
                while(tc%i==0) tc/=i;
            }
        }
        if(tc != 1)
        {
            save[ cnt++ ] = tc;
        }
        tc= mypow(p,a1-1)*(p-1);
        for(int i=0;i<cnt;i++)
        {
            save[i] = tc/save[i];
        }
        
        ll x0=0;
        for(int i=2;i<c;i++)
        {
            int flag=0;
            for(int j=0;j<cnt;j++)
            {
                if( Quk_Mul(i, save[j], c) ==1)
                {
                    flag=1;
                    break;
                }
            }
            if(flag==0)
            {
                x0=i;
                break;
            }
        }
        //找到原根x0后,然后找x0^a0 = b (mod c)
        ll a0 = BabyStep(x0 , b, c,mypow(p,a1-1)*(p-1));
        ll ord = mypow(p,a1-1)*(p-1);
        d = gcd(a,ord);
        if( a0%d != 0 ) return 0;
        return d;
    }
    
    ll xaeqbmodc(ll a,ll b,ll c)
    {
        ll ans=1;
        b%=c;
        ll tc=c;
        //然后对c进行因式分解
        for(ll i=2;i*i<=tc;i++)
        {
            if(tc%i==0)
            {
                ll tmpyz=1;
                int a1=0;
                while(tc%i==0)
                {
                    a1++;
                    tmpyz *= i;
                    tc/=i;
                }
                //然后对这个因子进行处理
                ans *= slove(a,b,tmpyz,i,a1);
                if(ans==0) break;
            }
        }
        if(tc!=1)
        {
            ans *= slove(a,b,tc,tc,1);
        }
        return ans;
    }

    其实这就是hdu3731了,关于思路可惜不是完全自己想的,稍微瞟了一眼大神的做法,突破了自己原先思维中不敢动c的想法,然后这题就会做了。这题A了也表示数论算是入了个门了,记得XIANBIN5在大一的时候就把数论学完了,并且把这题A了,我还是差太多啊。 接下来就是计算几何了。

    以下来自: http://www.cnblogs.com/dyllove98/archive/2013/08/05/3239030.html

    求方程:的解个数

     

    分析:设,那么上述方程解的个数就与同余方程组:的解等价。

     

    设同于方程的解分别是:,那么原方程的解的个数就是

     

    所以现在的关键问题是求方程:的解个数。

     

    这个方程我们需要分3类讨论:

     

    第一种情况:

     

    对于这种情况,如果方程的某个解设为,那么一定有,可以得到,即

     

    所以方程的解个数就是:,也就是

     

     

    第二种情况:

    这样也就是说p|B,设,本方程有解的充要条件是A|t,

    那么我们设t=kA,

     

    所以进一步有:,因为,这样又转化为第三种情况了。

    第三种情况:

     

    那么我们要求指标;求指标的话又要求原根。并且奇素数p的原根也是p^a的原根,所以说求个p的原根就好了。

    且如果有解,则解的个数为(A,φ(p^a))。

     

    求指标的话就是要解决A^x ≡ B (mod p^a)的问题。由于本情况保证了(p^a, B)=1,用个Baby-step-Giant-step就

    能解决问题。

     

    方程x^A ≡ B (mod p^a)有解,当且仅当(A,φ(p^a))|ind B。ind B表示B对于p^a的任一原根的指标。

  • 相关阅读:
    CentOS7系统基本操作
    python3安装
    nodejs基础【持续更新中】
    基于Jenkins实现持续集成【持续更新中】
    git之merge和rebase的区别
    服务器为什么这么慢?耗尽了CPU、RAM和磁盘I/O资源
    编程的四个境界
    Gunicorn独角兽
    Python 中 logging 日志模块在多进程环境下的使用
    vue+webpack怎么分环境进行打包
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5079779.html
Copyright © 2020-2023  润新知