题意:
让你求出一个数的全部原根,如果没有,输出-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;
}