原根
阶
若 \(gcd(a,m)=1\) ,使 \(a^l \equiv 1 (mod\ m)\) 成立的最小的 \(l\) ,称为 \(a\) 关于模 \(m\) 的阶
若 \(a\) 关于模 \(m\) 的阶为 \(l\),则 \(a^t\) 关于模 \(m\) 的阶 \(\frac{l}{gcd(t,l)}\)
原根
若 \(a\) 关于模 \(m\) 的阶为 \(\varphi(m)\) ,则称 \(a\) 是 \(m\) 的一个原根
- \(m\) 存在原根的充分必要条件是 \(m\) 的形式如 \(2,4,p^k,2p^k\) ,\(p\) 为质数
- \(m\) 的原根的个数为 \(\varphi(\varphi(m))\)
- 已知 \(m\) 的最小原根为 \(a\) ,那么 \(m\) 的原根就如 \(a^k\) 之类的,满足 \(k\) 与 \(\varphi(a)\) 互质
求解原根
-
先判断原根存不存在
-
求解最小的原根
-
求解所有的原根
原根的应用
更新中
洛谷模板题
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1000010;
int t,p,cnt,tot,ctans,fc[maxn],ans[maxn],pri[maxn],rt[maxn],q[maxn],phi[maxn];
void init(){// 欧拉筛 + 原根筛
phi[1]=1;
for(int i=2;i<=maxn-10;++i){
if(!q[i]){
pri[++tot]=i,phi[i]=i-1;
}
for(int j=1;j<=tot&&pri[j]*i<=maxn-10;++j){
q[i*pri[j]]=1;
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
rt[2]=rt[4]=1;
for(int i=2;i<=tot;++i){
for(int j=1;(1ll*j*pri[i])<=maxn-10;j*=pri[i]){
rt[j*pri[i]]=1;
}
for(int j=2;(1ll*j*pri[i])<=maxn-10;j*=pri[i]){
rt[j*pri[i]]=1;
}
}
return;
}
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int pow(int a,int b,int p){
int res=1;
while(b){
if(b&1)res=(1ll*res*a)%p;
a=(1ll*a*a)%p;
b>>=1;
}
return res;
}
void proc(int p){// 数字分解
for(int i=2;i*i<=p;i++){
if(p%i==0){
fc[++cnt]=i;
while(p%i==0)p/=i;
}
}
if(p>1)fc[++cnt]=p;
return;
}
bool chk(int x,int p){// 判断 x 是不是 p 的一个原根
if(pow(x,phi[p],p)!=1)return 0;
for(int i=1;i<=cnt;++i){
if(pow(x,phi[p]/fc[i],p)==1)return 0;
}
return 1;
}
int findrt(int p){ // 求最小的原根
for(int i=1;i<p;++i){
if(chk(i,p))return i;
}
return 0;
}
void getrt(int p,int x){// 已知最小的原根,求解对于整数 p 的所有原根
int prod=1;
for (int i=1;i<=phi[p];i++) {
prod=(1ll*prod*x)%p;
if (gcd(i,phi[p])==1) {
ans[++ctans]=prod;
}
}
return;
}
int main (){
init();
scanf("%d",&t);
while(t--){
int wtf;
scanf("%d%d",&p,&wtf);
if(rt[p]){
ctans=cnt=0;
proc(phi[p]);
int mn=findrt(p);
getrt(p,mn);
sort(ans+1,ans+ctans+1);
printf("%d\n",ctans);
for(int i=1;i<=ctans/wtf;++i)
printf("%d ",ans[i*wtf]);
printf("\n");
}
else printf("0\n\n");
}
return 0;
}
新赛季的开始