HDU - 4992 Primitive Roots 【原根】



题意: 

     

          让你求出一个数的全部原根,如果没有,输出-1;


题解“:


          首先先判断该数有无原根,

          一个数x若有原根 则必然满足 n=1,2,4,2p,p^r

          若有原根,再暴力枚举找到最小的原根,分解质因数phi(n);

          则从2~n-1 中有a 满足 a^phi(n)mod n=1  则a 不是n的原根。

  找到最小原根后

  如果g为n的原根,则gd为m的原根的充要条件是gcd(d,φ(n))=1;

       然后递推出所有结果。

1.有原根的数只有2,4,p^n,2p^n(p为质数,n为正整数)。

2.一个数的最小原根的大小是O(n0.25)的。

3.如果g为n的原根,则gd为m的原根的充要条件是(d,φ(n))=1;

4.如果n有原根,它的原根个数为φ(φ(n))。

5.一个数n的全体原根乘积模n余1

6.一个数n的全体原根总和模n余μ(n-1)(莫比乌斯函数)

#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn=1e6+5;
int a[10000];
bool p[maxn];
int ans[maxn];
int cnt;
ll gcd(ll a,ll b){
    ll t;
    while(b){
        t=a;a=b;b=t%b;
    }
    if(a>=0) return a;
    else return -a;
}
int phi(int x){
    if(p[x]) return x-1;
    int ret=x;
    for(int i=2;i<=x;++i){
        if(x%i==0){
            while(x%i==0) x/=i;
            ret=ret-ret/i;
        }
    }
    if(x>1)
        ret=ret-ret/x;
    return ret;
}
bool check(int x){
    if(x%2==0) x/=2;
    if(p[x]) return true;
    for(int i=3;i*i<=x;i+=2){
        if(x%i==0){
            while(x%i==0) x/=i;
            return x==1;
        }
    }
    return 0;
}

void get_x(int x){
    cnt=0;
    if(p[x]) return ;
    for(int i=2;i*i<=x;++i){
        if(x%i==0)
            a[++cnt]=i;
        if(i*i!=x) a[++cnt]=x/i;
        //while(x%i==0) x/=i;
    }
}
int kru(int a,int b,int mod){
    ll ret=1;
    ll t=a;
    while(b){
        if(b&1)
            ret=(ret*t)%mod;
        t=t*t%mod;
        b>>=1;
    }
    return (int)ret;
}
void init(){
    memset(p,1,sizeof(p));
    p[0]=p[1]=false;
    for(int i=2;i<maxn;++i)
        if(p[i]){
            for(int j=i+i;j<maxn;j+=i)
                p[j]=false;
        }
}
int main(){
    init();
    int n;
    while(~scanf("%d",&n)){
        if(n==2){
            puts("1");continue;
        }
        if(n==4){
            puts("3");continue;
        }
        if(check(n)==0) {
            puts("-1");continue;
        }
        int t=phi(n);
        //printf("phi(%d)=%d\n",n,t);
        get_x(t);
        int x=-1;
        for(int i=2;i<n;++i){
            int f=1;
            if(kru(i,t,n)!=1) continue;
            for(int j=1;j<=cnt;++j){
                if(kru(i,a[j],n)==1){
                    f=0;break;
                }
            }
            if(f){
                x=i;
                ans[0]=i;
                break;
            }
        }
        if(x==-1){
            puts("-1");continue;
        }
        cnt=0;
        for(int i=2;i<t;++i){
            if(gcd(i,t)==1)
                ans[++cnt]=kru(x,i,n);
        }
        sort(ans,ans+cnt+1);
        printf("%d",ans[0]);
        for(int i=1;i<=cnt;++i)
            printf(" %d",ans[i]);
        puts("");
    }
    return 0;
}


好的,关于 HDU4992 求所有原根的问题,我可以给出以下解答: 1. 首先,我们需要知道什么是原根原根是指模 n 意义下,所有与 n 互质的数 a 的最小正整数 k 次幂对 n 取模的值覆盖了所有与 n 互质的数。简单来说,就是如果一个数 a 是模 n 意义下的原根,那么 a 的任何正整数次幂对 n 取模的值都不相同,且能覆盖所有与 n 互质的数。 2. 为了求模 n 意义下的所有原根,我们需要先求出与 n 互质的数的个数 phi(n)。phi(n) 可以使用欧拉函数求出。 3. 然后,我们需要枚举模 n 意义下的所有数,判断它是否是原根。具体来说,对于每个 a,我们需要判断 a 的每个小于 phi(n) 的正整数次幂对 n 取模的值是否都不相同,且能覆盖所有与 n 互质的数。如果是,那么 a 就是模 n 意义下的原根。 4. 代码实现可以参考以下 Java 代码: ``` import java.util.*; public class Main { static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } static int phi(int n) { int res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res / i * (i - 1); while (n % i == 0) { n /= i; } } } if (n > 1) { res = res / n * (n - 1); } return res; } static int pow(int a, int b, int mod) { int res = 1; while (b > 0) { if ((b & 1) != 0) { res = res * a % mod; } a = a * a % mod; b >>= 1; } return res; } static boolean check(int a, int n, int phi) { for (int i = 1, j = pow(a, i, n); i <= phi; i++, j = j * a % n) { if (j == 1) { return false; } } return true; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int phi = phi(n); List<Integer> ans = new ArrayList<>(); for (int i = 1; i < n; i++) { if (gcd(i, n) == 1 && check(i, n, phi)) { ans.add(i); } } Collections.sort(ans); for (int x : ans) { System.out.print(x + " "); } System.out.println(); } } } ``` 其中,gcd 函数用于求最大公约数,phi 函数用于求欧拉函数,pow 函数用于快速幂求模,check 函数用于判断一个数是否是原根。在主函数中,我们依次读入每个 n,求出 phi(n),然后枚举模 n 意义下的所有数,判断它是否是原根,将所有原根存入一个 List 中,最后排序输出即可。 希望我的回答能够帮到你,如果你有任何问题,欢迎随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值