原根学习笔记
阶#
阶的定义#
设 m>1,且 gcd(a,m)=1,那么使得ar≡1(modm)成立的最小的正整数r称为a对模m的阶,记为δm(a)
阶的性质#
定理一:若 m>1 并且 gcd(a,m)=1,又满足 an≡1(modm),那么 δm(a)|n
定理二:δm(a)|φ(m)
原根#
原根的定义#
原根,是一个数学符号。设 m 是正整数,a 是整数,若 a 模 m 的阶等于 φ(m),则称 a为模 m 的一个原根。
原根存在的条件#
模 m 有原根的充要条件是 m=2,4,pk,2pk,其中 p 是奇素数(除了 2 以外的所有素数),k 是任意正整数。
原根的判定#
若 g 为模 m 的原根,则对于任意 φ(m) 的质因子 p,必有 g^{\frac{\varphi(m)}{p}}\not\equiv 1 \pmod m
求所有的原根#
最小原根是不大于 \sqrt[4]{m} 级别的。
因此,不妨枚举 [1,\sqrt[4]{m}] 的整数,得到最小原根 g。
再枚举 g^s 的指数 s,若 s 与 \varphi(m) 互质,则 g^s\bmod m 为一个原根。
由此可知,如果数 m 存在原根,则原根的个数为 \varphi(\varphi(m))
原根的性质#
a^0,a^1,a^2,\cdots,a^{\delta m(a)−1 } 模 m 两两不同余,且 a^{k}\%m=a^{(k+\delta_m(a))}\%m
代码#
复制#include<cstdio>
#include<cmath>
#include<algorithm>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e6+5;
bool not_pri[maxn];
int n,t,d,pri[maxn],phi[maxn];
void xxs(){
not_pri[0]=not_pri[1]=1;
phi[1]=1;
for(rg int i=2;i<maxn;i++){
if(!not_pri[i]){
pri[++pri[0]]=i;
phi[i]=i-1;
}
for(rg int j=1;j<=pri[0] && 1LL*i*pri[j]<maxn;j++){
not_pri[i*pri[j]]=1;
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
}
bool jud(rg int now){
if(now==2 || now==4) return 1;
if(now%2==0) now/=2;
for(rg int i=2;pri[i]<=now;i++){
if(now%pri[i]==0){
while(now%pri[i]==0){
now/=pri[i];
}
return now==1;
}
}
return 0;
}
int ksm(rg int ds,rg int zs,rg int mod){
rg int nans=1;
while(zs){
if(zs&1) nans=1LL*nans*ds%mod;
ds=1LL*ds*ds%mod;
zs>>=1;
}
return nans;
}
int sta[maxn],tp,g,ans[maxn],tp2;
void divid(rg int now){
rg int m=sqrt(now);
tp=0;
for(rg int i=2;i<=m;i++){
if(now%i==0){
sta[++tp]=i;
while(now%i==0) now/=i;
}
}
if(now>1) sta[++tp]=now;
}
int gcd(rg int aa,rg int bb){
return (bb==0)?aa:gcd(bb,aa%bb);
}
bool pd;
int main(){
xxs();
t=read();
while(t--){
n=read(),d=read();
if(jud(n)){
divid(phi[n]);
for(rg int i=1;;i++){
pd=1;
if(gcd(i,n)!=1) continue;
for(rg int j=1;j<=tp;j++){
if(ksm(i,phi[n]/sta[j],n)==1){
pd=0;
break;
}
}
if(pd){
g=i;
break;
}
}
rg int now=1;
tp2=0;
for(rg int i=1;tp2<phi[phi[n]];i++){
now=1LL*now*g%n;
if(gcd(phi[n],i)==1) ans[++tp2]=now;
}
std::sort(ans+1,ans+1+tp2);
printf("%d\n",phi[phi[n]]);
for(rg int i=1;i<=phi[phi[n]]/d;i++){
printf("%d ",ans[i*d]);
}
printf("\n");
} else {
printf("0\n\n");
}
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)