P6091 【模板】原根
前置知识:
阶
定义:
满足同余式子
性质:
-
-
若
a^n\equiv1\ (\bmod \ m) ,则\delta_m(a)\ \mid\ n 。 -
设
m \in \mathbf{N}^+ \ \ a,b \in \mathbf{Z},\gcd(a,m)=\gcd(b,m)=1 , 有\delta_m(a,b)=\delta_m(a)\times\delta_m(b)\ 的充分必要条件是\ \gcd(\delta_m(a),\delta_m(b))=1 。 -
设
k\in \mathbf{N}^\ \ m\in \mathbf{N}^+,a\in \mathbf{Z},\gcd(a,m)=1 ,则\delta_m(a^k)= \frac{ \delta_m(a) }{\gcd(\delta_m(a),k)} 。
原根
定义:
若
存在定理:
一个数
判定定理:
设
原根个数:
若一个数有原根,则它的原根的个数为
如对证明感兴趣可以去 oi wiki 上查看关于阶和原根及其定理的证明 ,取自 oi wiki。
扩充:
若
题意及主要思路:
题目很简单,就是求数
求解步骤:
1.初始化值域范围内的欧拉函数(线性筛)
时间复杂度
2.通过原根存在定理判断是否存在原根。
3.通过求出
4.通过最小原根找出所有原根。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
int phi[N],prime[N];
bool st[N];
int cnt,T;
vector<int>q,ans;
void euler_phi(int n){//初始化欧拉函数
phi[1]=1;
for(int i=2;i<=n;i++){
if(!st[i]){
prime[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;prime[j]<=n/i;j++){
st[prime[j]*i]=true;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
LL ksm(LL a,int b,int p){//用来找最小原根
LL res=1;
while(b){
if(b&1)res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
void cut_prime(int n){//分解数的欧拉函数用于找最小原根
for(int i=2;i<=n/i;i++){
if(n%i==0){
q.push_back(i);
while(n%i==0)n/=i;
}
}
if(n>1)q.push_back(n);
}
bool pd(int n){
if(n==2||n==4)return true;
if(n%2==0)n/=2;
for(int i=2;prime[i]<=n;i++){//若有原根则有唯一的质数分解
if(n%prime[i]==0){
while(n%prime[i]==0)n/=prime[i];
return n==1;
}
}
return false;
}
int main(){
euler_phi(N);//初始化所有数的欧拉函数
cin>>T;
for(int i=1;i<=T;i++){
int n,d;scanf("%d%d",&n,&d);
if(pd(n)){
q.clear();ans.clear();
cut_prime(phi[n]);
int need;LL last=1;//指数
for(int k=1;;k++){
bool flag=true;
if(__gcd(k,n)!=1)continue;
for(int j=0;j<q.size();j++){
if(ksm(k,phi[n]/q[j],n)==1){
flag=false;
break;
}
}
if(flag){
need=k;//最小原根
break;
}
}
for(int k=1;ans.size()<phi[phi[n]];k++){
last=last*need%n;
if(__gcd(phi[n],k)==1)ans.push_back(last);
}
sort(ans.begin(),ans.end());
printf("%d\n",phi[phi[n]]);//原根个数
for(int k=d-1;k<phi[phi[n]]/d*d && k<ans.size();k+=d){
printf("%d ",ans[k]);
}
cout<<endl;
}
else puts("0\n");
}
return 0;
}