求所有原根
# 题意
多测试样例,给定一个n求出来n所有的原根。
若不存在原根输出-1
2 ≤ n < 106
# 题解
先根据模n有原根的充要条件是n=2,4,pk,2pk,其中p是奇素数,k为任意正整数剪枝
判断当前n是不是有原根没有直接输出-1
暴力从2到n枚举最小的原根a,对φ(n)的所有质因子验证
aφ(n)/pi ≠ 1(mod n) i ∈ [1,n] 是不是都成立
成立则是最小的原根。然后用最小原根根据
若a为模n的原根,则ad为模n的原根的充要条件是gcd(d,φ(n))=1的性质
求出所有的,去重
1 #include <iostream> 2 #include <algorithm> 3 #include <vector> 4 #define pb push_back 5 using namespace std; 6 typedef long long ll; 7 const int N=1e6+10; 8 int primes[N+10],cnt; 9 ll euler[N]; 10 bool st[N+10]; 11 vector<ll>ans; 12 vector<int> factors; 13 void get_primes(){ 14 st[1] = 1; 15 euler[1] = 1; 16 for (int i = 2; i <= N; i ++ ) { 17 if (!st[i]) { 18 primes[cnt++] = i; 19 euler[i] = i - 1;//质数的欧拉函数 20 } 21 for (int j = 0; primes[j] <= N / i; j++) { 22 int t = primes[j] * i; 23 st[t] = true; 24 if (i % primes[j] == 0) { 25 euler[t] = euler[i] * primes[j]; 26 break; 27 } 28 euler[t] = euler[i] * (primes[j] - 1); 29 } 30 } 31 } 32 int gcd(int a,int b){return b?gcd(b,a%b):a;} 33 int qmi(ll a,ll k,ll p){ 34 ll res=1; 35 while(k){ 36 if(k&1) res=res*a%p; 37 a=a*a%p; 38 k>>=1; 39 } 40 return res; 41 } 42 43 void get_factors(int n) 44 { 45 factors.clear(); 46 for (int i = 2; i * i <= n; ++i) 47 { 48 if (n % i) continue; 49 factors.push_back(i); 50 do n /= i; 51 while (n % i == 0); 52 } 53 if (n > 1) factors.push_back(n); 54 } 55 bool judge(int n){ 56 // 模n有原根的充要条件是n=2,4,p^n,2p^n,其中p是奇素数,n为任意正整数 57 if(n%2==0) n/=2; 58 if(!st[n]) return true;//奇素数,有原根 59 for(int i=3;i*i<=n;i++){//偶素数只有2,从3开始即可 60 if(n%i==0){//遇到质因数除尽 61 while(n%i==0) n/=i; 62 return n==1;//能是有奇素数构成 63 } 64 } 65 return false; 66 } 67 68 int main(){ 69 ll n; 70 get_primes(); 71 while(cin>>n){ 72 ans.clear(); 73 if(n==2){ 74 puts("1");continue; 75 } 76 if(n==4){ 77 puts("3");continue; 78 } 79 if(!judge(n)) {//不存在原根 80 puts("-1");continue; 81 } 82 int phi=euler[n]; 83 int aa=-1; 84 get_factors(phi); 85 for(int a=2;a<n;a++){//求出一个最小的原根 86 bool flag=true; 87 aa=a; 88 if(qmi(a,phi,n)!=1) continue;//原根定义进行判断剪枝 89 for(int i=0;i<factors.size();i++){//枚举phi(n)的质因子 90 if(qmi(a,phi/factors[i],n)==1){//即小于phi(n)/p[i]也满足等式,不是原根 91 flag=false; 92 break; 93 } 94 } 95 if(flag){ 96 ans.pb(a);break; 97 } 98 } 99 if(ans.size()==0) puts("-1"); 100 else { 101 for(int i=2;i<=phi;i++){ 102 if(gcd(i,phi)==1) ans.pb(qmi(aa,i,n)); 103 } 104 sort(ans.begin(),ans.end()); 105 unique(ans.begin(),ans.end()); 106 for(int i=0;i<ans.size();i++){ 107 printf("%lld%c",ans[i],(i==ans.size()-1)?'\n':' '); 108 } 109 } 110 } 111 }