zoukankan      html  css  js  c++  java
  • 原根

    1、原根的定义:

    原根,是一个数学符号。设m是正整数,a是整数,若a模m的阶等于φ(m)(m的欧拉函数),则称a为模m的一个原根。

    阶:a和模m互质,使ad ≡1(mod m)成立的最小正整数d称为a对模m的阶。例如:22≡1(mod3),2对模3的阶为2。

    假设一个数g对于P来说是原根,那么gi mod p的结果两两不同,且有 1 < g < P , 0 < i < P.那么g可以称为是P的一个原根。

    归根到底就是 gP-1 ≡ 1 (mod P)当且仅当质数为P-1的时候成立(P为素数).

    求原根目前的做法只能是从2开始枚举,然后暴力判断g^(P-1) = 1 (mod P)是否当且当指数为P-1的时候成立,而由于原根一般都不大,所以可以暴力得到。

    2、原根的性质:

    (1)可以证明,如果正整数(a,m) = 1 和正整数d满足ad ≡ 1(mod 7),则d整除φ(m)。因此Ordm(a)整除φ(m)。在例子中,

    当a = 3 时,我们仅需要验证3的1、2、3和6次方模7的余数即可。

    (2)记 δ = Ordm(a),则a1 ,.... aδ-1 构成模m的简化剩余系数。

    (3)模m有原根的充要条件是m = 1,2 , 4 , p , 2p , pn , 其中p是奇质数,n是任意正整数。

    (4)对正整数(a,m)= 1 , 如果a是模m的原根,那么a是整数n乘法群(即加法群 Z/mZ的可逆元,也就是所有与 m 互素的正整数构成的等价类构成的乘法群)Zn的一个生成元。由于Zn有φ(m)个元素,而它的生成元的个数就是它的可逆元个数,即φ(φ(m))个,因此当模m有原根时,它有φ(φ(m))个原根

    3、求质数最小原根

    求质数最小原根:对于质数p,φ(p) = p - 1 ,根据费马小定理,ap-1≡1(mod p) 成立a为大于1的整数。所有只需验证没有比p-1小的数k

    使得ak≡1(mod p).

    而k不需要全部枚举,只需枚举p-1的质因数即可。(如果x为p-1的质因子,且ax ≡ 1(mod p),那么x的倍数nx显然也满足anx ≡ 1(mod p) ,所有p-1不为a对模p的阶(不是最小),即不是原根)。

    素数p(3<=p<=1e9),一般对于要多次分解质因数时,可以先筛选出素数,然后再素数里进行质因数分解。

    因为这题只需进行一次,可以不需要筛素数,直接分解O(√n)。

    首先求质幂分解Φ(m) = p1e1 * p2e2 * ...*pkek

    然后枚举g,若恒不满足gΦ(m)/p ≡ 1 mod(p) 其中i = 1,2....k.

    则g是m的原根。

    const int maxn = 1e5+9;
    const int N = 1e6+9;
    int vis[N], prime[maxn] , len , pf[maxn] , len1;
    
    void Erasieve(){
        rep(i , 2 , N){
            if(!vis[i]){
                prime[++len] = i ;
                for(int j = i * i ; j <= N ; j += i){
                    vis[j] = 1 ;
                }
            }
        }
    }
    
    void oulasieve(){
        rep(i , 2 , N){
            if(!vis[i]){
                prime[++len] = i ;
            }
            for(int j = 1 ; j <= len && prime[j] * i <= N ; j++){
                vis[prime[j]*i] = 1;
                if(i % prime[j] == 0) break;
            }
        }
    }
    
    void divide(int x){
        for(int i = 1 ; i <= len && prime[i] * prime[i] <= x; i++){
            if(x%prime[i]==0){
                pf[++len1] = prime[i];
                while(x % prime[i] == 0){
                    x /= prime[i] ;
                }
            }
        }
        if(x > 1) pf[++len1] = x ;
    }
    
    /*void divide2(int x){
        for(int i = 2 ; i * i <= x ; i++){
            if(x % i == 0){
                phi[++len1] = i ;
                while(x % i == 0) x /= i ;
            }
        }
    }*/
    
    int quickpow(int a , int b , int p){
        int ans = 1 ;
        while(b){
            if(b&1){
                ans = ans * a % p ;
            }
            b >>= 1 ;
            a = a * a % p ;
        }
        return ans ;
    }
    
    void solve(){
        oulasieve();
        int p ;
        cin >> p ;
        divide(p-1);
        rep(i , 2 , p-1){
            int flag = 1 ;
            rep(j , 1 , len1){
                if(quickpow(i , (p-1)/pf[j] , p) == 1){
                    flag = 0 ;
                    break;
                }
            }
            if(flag == 1){
                cout << i << endl;
                break;
            }
        }
    }
    
  • 相关阅读:
    461. Hamming Distance
    Myeclipse中WebServlet cannot be resolved to a type报错
    注解方式配置Servlet(Servlet3.0)
    Oracle连接池操作
    最短路径算法
    编写学生类Stu
    编写程序,统计某旅馆住宿客人的总数,要求输入客人姓名,输出客人编号(按先后顺序自动生成),姓名以及总人数。
    货物管理系统
    c# 利用动态库DllImport("kernel32")读写ini文件(提供Dmo下载)
    shut
  • 原文地址:https://www.cnblogs.com/nonames/p/12431624.html
Copyright © 2011-2022 走看看