原根和离散对数BSGS求法(高次同余方程)

原根&离散对数


一.原根

1.定义:

(a与m互质)使\large a^{d}\equiv 1(mod m)成立的最小的d(记住原根是a,不是d!)

2.原根的性质:一般给出p(有时叫m)

1.具有原根的数字仅有以下几种形式:\large 2,4,\large p^{n},2p^{n}(p是奇质数)

2.一个数的最小原根的大小不超过\large m^{1/4}

3.原根个数Φ(Φ(m))个,m为质数则原根个数Φ(m-1)

3.求解原根的基本步骤:

  1. 判断一个数是否有原根。(通过性质1,枚举质数即可)
  2. 求得最小原根。(通过性质2,依次枚举2~\large m^{1/4}判断即可)
  3. 求出所有原根。(通过性质3,枚举次数d即可)
  4. 简化版:

4.代码

5.应用 HDU5377  (准备另开一篇)

poj 1284 性质3质数的原根个数

原根可以把求指数问题转化为求对数问题,这样实现乘到加的转换,复杂度大大降低

 

 

2.离散对数


1.定义
普通对数:     \large a^{x}=b     记做\large x=log{_{b}}a
离散对数就是把这个放在了模意义下,即求解方程: a^x≡b(mod p)

2.求解方法(扩展版BGBS 大步小步算法)  参考代码

这个模板用的二分,复杂度多个logn,有些模板用map或hash,hash可以根号n解决

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define Inf (1<<29)
#define LL long long
using namespace std;
const int MM=110;
const long long MOD=1000000007;
///扩展大步小步算法
struct baby///小步算法预存的结构体定义
{
    long long b,j;
    bool operator < (const baby &other)const{
        if(b==other.b)return j0)
    {
        if(y&1)ans=(ans*x)%mod;
        x=(x*x)%mod;
        y>>=1;
    }
    return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
    long long l=0,r=m-1,ans=-1;
    while(r>=l)
    {
        long long mid=(r+l)/2;
        if(babyv[mid].b>=num){
            if(babyv[mid].b==num)
                ans=babyv[mid].j;
            r=mid-1;
        }
        else l=mid+1;
    }
    return ans;
}
///A^x=B(modC)求解x,gcd(A,C)不一定等于1,无解返回-1
long long ex_babystep_giantstep(long long A,long long B,long long C)
{
    for(long long i=0;i<=100;i++)///先在小于100的数里面测试
        if(q_pow(A,i,C)==B%C)return i;
    ///消因子, 将A^x=B%C化为d*A^(x – n)=B%C
    long long g,n=0,d=1;
    while((g=gcd(A,C))!=1)
    {
        if(B%g)return -1;///无解
        n++;
        B/=g;
        C/=g;
        d=(d*A/g)%C;
    }
    ///无扩展小步大步操作
    long long m=ceil(sqrt(C)),ans=1;
    for(long long j=0;j

 


 

你可能感兴趣的:(—————数论—————,筛法,解方程)