zoukankan      html  css  js  c++  java
  • 原根

    Definition

    • 指数:设 (m>1) 为整数, (a) 为与 (m) 互素的数,则使得 (a^e equiv 1 (mod m)) 成立的是最小正整数 (e) 叫做 (a) 对模 (m) 的指数,记作 (ord_{m}{a})

    • 原根:若 (a) 对 模 (m) 的指数为 (varphi(m)) ,则 (a) 叫做模 (m) 的原根

    定理

    1. (m>1) 是整数,(a) 是与 (m) 互素的整数,则整数 (d) 使得 (a^d equiv 1 (mod m)) 成立的充分必要条件为 (ord_m(a) | d)

    2. (m>1) 是整数,(a) 是与 (m) 互素的整数,则

      [1 = a^0 , a , ....... , a^{ord_m(a)-1} ]

      (m) 两两不同于,特别的,当 (a)(m) 的原根时,有 (ord_m(a) = varphi(m)) ,这 (varphi(m)) 个数组成模 (m) 的简化剩余系

    3. (m>1) 是整数,(a) 是与 (m) 互素的整数,设 (d) 为非负整数,则

      [ord_m{(a^d)} = frac{ord_m(a)}{(d,ord_m(a))} ]

      故有推论:设 (m>1) 是整数,(g) 是模 (m) 的原根,设 (d geq 0) 为整数,则 (g^d) 为模 (m) 的原根当且仅当 ((d,varphi(m)) = 1)

    4. (m>1) 是整数,如果模 (m) 存在一个原根 (g) ,则模 (m) 的原根有 (varphi(varphi(m))) 个不同的原根

    5. (m>1) 是整数,(a) , (b) 是与 (m) 互素的整数,如果 ((ord_m(a),ord_m(b)) = 1) ,则

      [ord_m(a,b) = ord_m(a) · ord_m(b) ]

      成立,反之亦然

    6. (m,n>1) 是整数,(a) 是与 (m) 互素的整数,则:若 (n|m) ,则 (ord_n(a) | ord_m(a))

      同时,若 ((n,m) =1) ,则

      [ord_{mn}(a)=[ord_m(a),ord_n(a)] ]

    7. (p) 原根存在的充要条件为 (m=2 , 4 , p^a , 2p^a)

    例题

    分析

    对于本题,首先我们可以应用定理7,那么所有的不能表示为 (2,4,p^a,2p^a) 的数都没有原根

    其次,我们可以求出最小原根,然后通过定理3的推论,将所有的原根求出

    那么如何求最小原根呢,首先想到的方法便是直接扫描判断,一般而言,这个方法就已经很好了,因为大部分数的最小原根要么没有,要么很小

    那么判断时,我们枚举到的当前数字 (g) ,显然有 (g^{varphi(m)} equiv 1 (mod m)) (欧拉定理),那么,我们可以应用定理1,将 (varphi(m)) 进行质因数分解,设其质因数为(p_i),如果 (g)(m) 的一个原根,那么它的(frac{varphi(m)}{p_i}) 次方必然在模 (m) 意义下不为 (1) , 对于所有质因子都满足上述条件的 (g) ,即为最小原根

    Solution

    通过分析,我们可以先用线性筛将 (varphi(i)) 的大小以及有原根的数筛选出来

    之后,我们就可以通过依次判断求得最小原根,然后从 (1) ~ (varphi(m)) 进行枚举,挑选出其中与 (varphi(m)) 互素的数作为指数,利用快速幂处理得到其他的原根

    code

    #include<iostream>
    #include<cstdio>
    #include<math.h>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #include<bitset>
    #include<queue>
    #include<vector>
    #define ll long long
    
    const ll maxn=1e6+10;
    ll t,n,cnt,d,tot,sum;
    ll vis[maxn],prime[maxn],phi[maxn],yg[maxn],yz[maxn],ans[maxn];
    
    inline void cle()
    {
    	tot=sum=0;
    }
    
    inline ll gcd(ll a,ll b)
    {
    	return b==0 ? a : gcd(b,a%b);
    }
    
    inline void pre(ll x)
    {
    	phi[1]=1;
    	
    	for(int i=2;i<=x;i++)
    	{
    		if(!vis[i])
    		{
    			vis[i]=1;
    			prime[++cnt]=i;
    			phi[i]=i-1;
    		}
    		
    		for(int j=1;j<=cnt&&i*prime[j]<=x;j++)
    		{
    			vis[i*prime[j]]=1;
    						
    			if(i%prime[j]==0)
    			{
    				phi[i*prime[j]]=phi[i]*prime[j];
    				break;
    			}
    			
    			phi[i*prime[j]]=phi[i]*(prime[j]-1);
    		}
    	}
    	
    	yg[2]=yg[4]=1;
    	
    	for(int i=2;i<=cnt;i++)
    	{
    		for(int j=1;j*prime[i]<=x;j*=prime[i]) yg[j*prime[i]]=1;
    		for(int j=2;j*prime[i]<=x;j*=prime[i]) yg[j*prime[i]]=1;
    	}
    }
    
    inline ll ksm(ll a,ll b,ll p)
    {
    	ll ret=1;
    	while(b)
    	{
    		if(b&1) ret=ret*a%p;
    		a=a*a%p;
    		b>>=1;
    	}
    	return (ret%p);
    }
    
    inline void fj(ll x)
    {
    	for(int i=1;i<=cnt&&prime[i]<=x;i++)
    	{
    		if(x%prime[i]==0) yz[++tot]=prime[i];
    	}
    }
    
    inline ll check(ll ds,ll x)
    {
    	if(ksm(ds,phi[x],x)!=1) return 0;
    	
    	for(int i=1;i<=tot;i++)
    	{
    		if(ksm(ds,phi[x]/yz[i],x)==1) return 0;
    	}
    	
    	return 1;
    }
    
    inline ll getyg(ll x)
    {	
    	for(int i=1;i<=x;i++)
    	{
    //		printf("123 %lld
    ",i);
    		if(check(i,x))
    		{
    			return i;
    		}
    	}
    	
    //	return 0;
    }
    
    inline void qj(ll p,ll x)
    {
    	ll ret=1;
    	
    	for(int i=1;i<=phi[p];i++)
    	{
    		ret=ret*x%p;
    		
    		if(gcd(i,phi[p])==1) ans[++sum]=ret;
    	}
    }
    
    int main(void)
    {
    //	freopen("2.in","r",stdin);
    //	freopen("2.out","w",stdout);
    	scanf("%lld",&t);
    	
    	pre(maxn-10);
    	
    	while(t--)
    	{
    		cle();
    		
    		scanf("%lld %lld",&n,&d);
    		
    		fj(phi[n]);
    		
    //		printf("qaq %lld
    ",tot);
    //		printf("qwq %lld
    ",phi[n]);
    		
    		if(!yg[n])
    		{
    			printf("0
    
    ");
    			continue;
    		}
    		
    		ll minn=getyg(n);
    		
    //		printf("zzz %lld
    ",minn);
    		
    		qj(n,minn);
    		
    		std::sort(ans+1,ans+sum+1);
    		
    		printf("%lld
    ",sum);
    		
    		for(int i=d;i<=sum;i+=d)
    		{
    			printf("%lld ",ans[i]);
    		}
    		
    		printf("
    ");
    	}
    	
    	return 0;
    }	
    
  • 相关阅读:
    PHP类(一)-类的实例化
    PHP函数(六)-匿名函数(闭包函数)
    PHP函数(五)-回调函数
    javaIO-字符流
    split 命令
    hadoop的增删改查
    Hadoop的MR
    java的序列化和反序列化
    字符串格式化-String类format方法
    Avro从入门到入土
  • 原文地址:https://www.cnblogs.com/jd1412/p/14280461.html
Copyright © 2011-2022 走看看