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 (2≤d≤φ(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':' ');
}
}
}
}