HDU 4992 Primitive Roots(原根性质)

Primitive Roots

Problem Description
We say that integer x, 0 < x < n, is a primitive root modulo n if and only if the minimum positive integer y which makes xy = 1 (mod n) true is φ(n) .Here φ(n) is an arithmetic function that counts the totatives of n, that is, the positive integers less than or equal to n that are relatively prime to n. Write a program which given any positive integer n( 2 <= n < 1000000) outputs all primitive roots of n in ascending order.

Input
Multi test cases.
Each line of the input contains a positive integer n. Input is terminated by the end-of-file seperator.

Output
For each n, outputs all primitive roots of n in ascending order in a single line, if there is no primitive root for n just print -1 in a single line.

Sample Input

4
25

Sample Output

3
2 3 8 12 13 17 22 23

题意
求所有原根,没有原根输出-1

题解
就是利用原根性质,但是慎重点开此题,超级恶心
在这里插入图片描述
从一开始的直接存所有原根,T掉了。
然后找到原根的性质有一条是对于 a a a是模 m m m的一个原根,则对所有 d   ( 2 ≤ d ≤ φ ( m ) ) , g c d ( d , φ ( m ) ) = = 1 d\ (2\leq d\leq \varphi(m)),gcd(d,\varphi(m))==1 d (2dφ(m)),gcd(d,φ(m))==1, a d % m a^d\%m ad%m也是模 m m m的一个原根
找到最小的原根然后通过该性质找到所有原根,然后排序去重。依旧T掉了。
然后再多加一个判断条件:一个数有原根的充要条件是该数为 2 , 4 , p t , 2 p t 2,4,p^t,2p^t 2,4,pt,2pt,其中 p p p是奇质数, t t t是正整数,我们将 2 p t 2p^t 2pt也转化为 p t p^t pt判断。
终于是过了。。。恶心,这么多性质都用上了还是用了1123ms

刚刚写完博客,突然想起这是多组输入,我把phi打表会不会更快一点(滑稽),然后现实打脸打的太狠,竟然1ms都没提升。。。
在这里插入图片描述
然后我又尝试把vector用数组表示,结果更慢了???
在这里插入图片描述
算了算了,1123ms就这样吧,也不知道700+ms的神仙是什么情况。
代码

#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <ctime>
using namespace std;
#define me(x,y) memset(x,y,sizeof x)
#define MIN(x,y) (x) < (y) ? (x) : (y)
#define MAX(x,y) (x) > (y) ? (x) : (y)
#define SGN(x) ((x)>0?1:((x)<0?-1:0))
#define ABS(x) ((x)>0?(x):-(x))
#define LOCAL local_

typedef long long ll;
typedef unsigned long long ull;

const int maxn = 1e6+10;
const ll INF = 0x3f3f3f3f;
const int MOD = 1e9+7;
const int eps = 1e-8;
//素数打表
int prime[maxn+10],vis[maxn+10];
void get_prime(){
    vis[1]=1;
    for(int i = 2; i <= maxn; ++i){
        if(!vis[i]) prime[++prime[0]]=i;
        for(int j = 1; j <= prime[0] && i*prime[j] <= maxn; ++j){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
//快速幂
int qpow(ll a,ll b,ll p){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}
//欧拉函数
int get_phi(int x){
    if(!vis[x]) return x-1;
    int res=x;
    for(int i = 2; i*i <= x; ++i){
        if(x%i == 0){
            res = res/i*(i-1);
            while(x%i == 0) x /= i;
        }
    }
    if(x > 1) res = res/x*(x-1);
    return res;
}
ll q[maxn];
vector<ll> v;
//分解因子
void del(int phi){
    if(!vis[phi]) return ;
    for(int i = 2; i*i <= phi; ++i){
        if(phi%i==0){
            if(i*i == phi) q[++q[0]]=i;
            else q[++q[0]]=i,q[++q[0]]=phi/i;
        }
    }
    return ;
}
//判断该数是否存在原根
bool judge(int x){
    if(x%2 == 0) x /= 2;
    if(!vis[x]) return true;
    for(int i =2; i*i <= x; ++i){
        if(x%i == 0){
            while(x%i == 0) x/=i;
            return x==1;
        }
    }
    return false;
}
int main(){
    ll m;
    get_prime();
    while(cin>>m){
        v.clear();
        // cin>>m;
        if(m == 2){
            printf("1\n");continue;
        }
        if(m == 4){
            printf("3\n");continue;
        }
        if(!judge(m)){
            puts("-1");continue;
        }
        q[0]=0;
        int phi=get_phi(m);
        int G=-1;
        del(phi);
        for(int g=2;g<m; ++g){
            int fg=1;
            G=g;
            if(qpow(g,phi,m)!=1) continue; //g^(phi(m))=1 (mod m)
            for(int i = 1; i <= q[0]; ++i){     //枚举phi(m)因子
                if(qpow(g,q[i],m)==1){
                    fg=0;break;
                }
            }
            if(fg) {v.push_back(g);break;}
        }
        if(v.size()==0){
            puts("-1");
        }
        else{
            for(int i = 2; i <= phi; ++i){
                if(__gcd(i,phi)==1) v.push_back(qpow(G,i,m));
            }
            sort(v.begin(),v.end());
            unique(v.begin(),v.end());
            for(int i = 0; i < v.size(); ++i){
                printf("%lld%c",v[i],(i==v.size()-1)?'\n':' ');
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值