题意:给一个正整数 n ( n > = 2 ) n(n>=2) n(n>=2),求她的所有原根,若不存在输出 − 1 -1 −1
思路:
由定义1:一个数
m
m
m存在原根的充要条件为:
m
=
2
,
4
,
p
a
,
2
∗
p
a
m=2,4,p^a,2*p^a
m=2,4,pa,2∗pa(
p
p
p为奇素数)
可以特判输出
−
1
-1
−1的情况。
又由定义2:若
G
G
G为
n
n
n的原根,则当
g
c
d
(
i
,
φ
(
n
)
)
=
=
1
gcd(i,\varphi(n)) == 1
gcd(i,φ(n))==1,
G
i
G^i
Gi也为
n
n
n的原根
可以通过先求出
n
n
n的最小原根,来枚举得到其他的合法原根。
对于求一个数的最小原根就是一个很基础的问题了,此处需要注意的是 n n n可能是合数,则 a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)} \equiv 1 (mod \ n) aφ(n)≡1(mod n)当 g c d ( a , n ) ≠ 1 gcd(a,n) \neq 1 gcd(a,n)̸=1不成立,故需要提前特判。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int A = 1e6 + 10;
int pri[A],phi[A],ans[A],q[A],n,tot;
bool vis[A];
int gcd(int a,int b){ return b?gcd(b,a%b):a;}
void init(){
tot = 0;phi[1] = 1;
for(int i=2 ;i<A ;i++){
if(!vis[i]){pri[++tot] = i;phi[i] = i-1;}
for(int j=1 ;j<=tot&&i*pri[j]<A ;j++){
vis[i*pri[j]] = 1;
if(i%pri[j] == 0){
phi[i*pri[j]] = pri[j] * phi[i];break;
}
phi[i*pri[j]] = phi[pri[j]] * phi[i];
}
}
}
ll fast_pow(ll a,ll b){
ll res = 1;
while(b){
if(b&1) res = res*a%n;
a = a*a%n;
b >>= 1;
}
return res;
}
int get_G(){
int t = 0,tem = phi[n];
for(int i=1 ;i<=tot && pri[i]*pri[i]<=tem ;i++){
if(tem%pri[i] == 0){
q[++t] = pri[i];
while(tem%pri[i]==0) tem/=pri[i];
}
}
if(tem>1) q[++t] = tem;
for(int i=2;i<n;i++){
if(gcd(i,n) != 1) continue;
bool flag = 0;
for(int j=1 ;j<=t ;j++) if(fast_pow(i,phi[n]/q[j]) == 1) {flag=1;break;}
if(!flag) return i;
}
return -1;
}
bool check(int n){
if(n==2 || n==4) return true;
if(n%2 == 0) n >>= 1;
for(int i=2 ;pri[i]<=n ;i++){
if(n%pri[i] == 0){
while(n%pri[i] == 0)n/=pri[i];
return n==1?true:false;
}
}
return false;
}
void solve(){
if(!check(n)) {puts("-1");return;}
if(n == 2) {puts("1");return;}
int G = get_G();
int twt = 0;
for(int i=1,k=G ;i<phi[n] ;i++){
if(gcd(i,phi[n]) == 1){
ans[++twt] = k;
}
k = 1LL*k*G%n;
}
sort(ans+1,ans+1+twt);
for(int i=1 ;i<=twt ;i++) printf("%d%c",ans[i],i==twt?'\n':' ');
}
int main(){
init();
while(~scanf("%d",&n)){
solve();
}
return 0;
}