原根
知识点
阶
-
定义:由欧拉定理可知,对\(a\in \mathbb{Z},m\in\mathbb{N^* }\),若\(gcd(a,m)=1\) ,则 \(a^{\varphi(m)}\equiv 1\pmod m\)
因此满足同余式\(a^n\equiv 1\pmod m\)的最小正整数\(n\)存在,这个\(n\)称作\(a\)模\(m\)的阶,记作\(\delta_m(a)\) -
性质:
-
\(a^1,a^2,...,a^{\delta_m(a)}\)模\(m\)两两不同余
-
若\(a^n\equiv 1\pmod m\),则\(\delta_m(a)\mid n\)
推论1:若\(a^p\equiv a^q\),则有\(p\equiv q \pmod{\delta_m(a)}\)
推论2:若\(gcd(a,m)=1\),\(\delta_m(a)\mid\varphi(m)\) -
设\(m\in\mathbb{N^* },a,b\in\mathbb{Z},gcd(a,m)=gcd(b,m)=1\),则\(\delta_m(a\cdot b)=\delta_m(a)\cdot \delta_m(b)\) 的充分条件是\(gcd(\delta_m(a),\delta_m(b))=1\)
-
设\(k\in\mathbb{N},m\in\mathbb{N^* },a\in\mathbb{Z},gcd(a,m)=1\),则\(\delta_m(a^k)=\frac{\delta_m(a)}{gcd(\delta_m(a),k)}\)
-
若\(p\) 为素数,则\(\delta_p(g^i)=\delta_p(g)\)的充要条件为\(gcd(\delta_p(g),i)=1 (g\in\mathbb{N^* })\)。\(\\g^i\)也可以表示为\(g^{gcd(\delta_p(g),i)\cdot r} (r\in\mathbb{N^* })\)
原根
-
定义:设\(m\in\mathbb{N^* },a\in\mathbb{Z}\),若\(gcd(a,m)=1\),且\(\delta_m(a)=\varphi(m)\),则称\(a\)为\(m\)的原根
-
定理:
-
原根判定定理:设\(m\geqslant3,gcd(a,m)=1\),则\(a\)是模\(m\)的原根的充要条件是,对于\(\varphi(m)\)的每个素因数\(p\),都有
$a^{\frac{\varphi(m)}{p}}\not\equiv1\pmod m $ -
原根个数:若一个数\(m\)有原根,则它原根的个数为\(\varphi(\varphi(m))\)
-
原根存在定理:
引理1:设\(a\)与\(b\)是与\(p\)互素的两个整数,则存在\(c\in\mathbb{Z}\)使得\(\delta_p(c)=lcm(\delta_p(a),\delta_p(b))\)
定理1:一个数\(m\)存在原根当且仅当\(m=2,4,p^\alpha,2\cdot p^\alpha\),其中\(p\)为奇素数,\(\alpha\in\mathbb{N^* }\)
引理2:存在模\(p\)的原根\(g\),使得\(g^{p-1}\not\equiv1\pmod{p^2}\)
定理2:对于奇素数\(p,\alpha\in\mathbb{N^* }\),\(p^\alpha\) 有原根
定理3:对于奇素数\(p,\alpha\in\mathbb{N^* }\),\(2\cdot p^\alpha\) 的原根存在
定理4:对于\(m\ne2,4\),且不存在奇素数\(p\)及\(\alpha\in\mathbb{N^* }\)使得\(m=p^\alpha,2\cdot p^\alpha\),模\(m\)的原根不存在 -
若\(gcd(g,n)\)且(n>0),则\(g\)为\(n\)的一个原根的充要条件为\(S=\{g^1,g^2...g^{\varphi(n)}\}\)为\(n\)的一组简化剩余系
-
若奇素数\(p\)的原根\(g\)满足\(g^{p-1}\not\equiv1\pmod {p^2}\),则对于每一个\(a\geqslant2\),有\(g^{\varphi(p^{a-1})}\not\equiv1\pmod {p^a}\)
-
若\(p\)为素数,\(a\)为整数且\(p\nmid a\),则在一个模\(p\)的完全剩余系中恰有\(\varphi(\delta_p(a))\)个数模\(p\)的阶为\(\delta_p(a)\)
-
对于任意整数\(h\)使得\(\delta_p(h)=\delta_p(a)\),定存在\(a^{d_i} (i\in[1,\varphi(\delta_p(a))\cap\mathbb{Z}])\)在模\(p\)意义下与\(h\)同余
-
若\(p\)为整数且有一个原根\(g\),则\(p\)恰有\(\varphi(\varphi(p))\)个在模\(p\)意义下不同余的原根,它们由集合\(S=\{g^i|1\leqslant i\leqslant\varphi(p),gcd(p,i)=1\}\)中的数给出
求原根
- 线性筛预处理所有质数和有原根的数,\(O(n)\)
- 将 \(\varphi(n)\) 分解因数,由于质数已经筛出,复杂度 $O(n^{0.5}/\log n) $
- 快速幂求出最小原根,复杂度大概是 \(O(n^{0.25}\log n\log\log n)\)
- 通过最小原根求出所有原根,需要进行 \(\varphi(n)\) 次求最大公约数, \(O(n\log n)\)
- 排序,从小到大输出,$ O(n\log n)$
总复杂度\(O(Tn\log\log\log n)\)
code
#include<bits/stdc++.h>
#define il inline
#define cs const
#define ri register
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri char c=getchar();ri bool f=0;
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10|48),void();
}
} using namespace Q;
cs int N=1e6;
namespace ovo{
int ss[N],fi[N+1],cnt;bool b[N+1];
il void init(int n){
fi[1]=b[2]=b[4]=1;
for(ri int i=2;i<=n;++i){
if(!fi[i]) fi[i]=i-1,ss[++cnt]=i;
for(ri int j=1;j<=cnt&&1ll*ss[j]*i<=n;++j){
if(i%ss[j]) fi[i*ss[j]]=fi[i]*fi[ss[j]];
else {fi[i*ss[j]]=fi[i]*ss[j];break;}
}
}
for(ri int i=2;i<=cnt;++i){
for(ri int j=1;1ll*j*ss[i]<=n;){
j*=ss[i],b[j]=1;
}
for(ri int j=2;1ll*j*ss[i]<=n;){
j*=ss[i],b[j]=1;
}
}
return;
}
il int qpow(int a,int b,int p){
ri int as=1;
while(b>0){
if(b&1) as=1ll*as*a%p;
a=1ll*a*a%p,b>>=1;
}
return as;
}
} using namespace ovo;
namespace qwq{
int q[N],tq,g[N],tg;
il void calc(int n){
tq=0;
for(ri int i=1;i<=cnt&&1ll*ss[i]*ss[i]<=n;++i){
if(!(n%ss[i])){
q[++tq]=ss[i];
while(!(n%ss[i])) n/=ss[i];
}
}
if(n>1) q[++tq]=n;
return;
}
il void get_min(int n){
g[0]=0;
for(ri int i=1;i<n;++i){
if(qpow(i,fi[n],n)==1){
g[0]=i;
for(ri int j=1;j<=tq;++j){
if(qpow(i,fi[n]/q[j],n)==1){
g[0]=0;break;
}
}
if(g[0]) break;
}
}
return;
}
il void get_g(int n){
if(!b[n]) return;
calc(fi[n]),get_min(n);
for(ri int i=1,mul=g[0];i<=fi[n];++i){
if(__gcd(i,fi[n])==1) g[++tg]=mul;
mul=1ll*mul*g[0]%n;
}
return;
}
il void prt(int d){
wt(tg),putchar(10);
sort(g+1,g+tg+1);
for(ri int i=d;i<=tg;i+=d){
wt(g[i]),putchar(32);
}
putchar(10),tg=0;
return;
}
} using namespace qwq;
signed main(){
init(N);
ri int t=rd(),n,d;
while(t--){
n=rd(),d=rd();
get_g(n),prt(d);
}
return 0;
}
这样会快很多
code
#include<bits/stdc++.h>
#define il inline
#define ri register
#define cs const
namespace Q{
il int rd(){
ri int x=0;ri char c=getchar();ri bool f=0;
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10|48),void();
}
} using namespace Q;
cs int N=1e6+7;
int ss[N],fi[N],fc[9],u[11],v[11],a[N];
bool f[N],b[N],p[N],q[N];
il void init(int n){
b[2]=b[4]=fi[1]=1;
ri int i,j,k,t=0;
for(i=2;i<=n;++i){
if(!f[i])ss[++t]=i,fi[i]=i-1;
for(j=1;k=i*ss[j],k<=n&&j<=t;++j){
f[k]=1;
if(!(i%ss[j])){
fi[k]=fi[i]*ss[j];
break;
}
fi[k]=fi[i]*fi[ss[j]];
}
}
for(i=2;i<=t;++i){
for(j=1;j*1ll*ss[i]<=n;b[j*=ss[i]]=1);
for(j=2;j*1ll*ss[i]<=n;b[j*=ss[i]]=1);
}
}
il int qp(int a,int b,int p){
ri int r=1;
while(b){
if(b&1)r=r*1ll*a%p;
a=a*1ll*a%p,b>>=1;
}
return r;
}
int main(){
ri int T=rd(),n=0,m,d,i,j,k,t,o,s;
for(i=1;i<=T;++i)u[i]=rd(),v[i]=rd(),n=n>u[i]?n:u[i];
init(n);
for(o=1;o<=T;++o){
n=u[o],d=v[o];
if(!b[n]){
puts("0\n");
continue;
}
for(i=1,j=m=fi[n],t=0;ss[i]*ss[i]<=j;++i){
if(!(j%ss[i])){
fc[++t]=s=ss[i];
do j/=s;while(!(j%s));
for(k=s;k<=m;k+=s)p[k]=1;
}
}
if(j>1){
fc[++t]=j;
for(k=j;k<=m;k+=j)p[k]=1;
}
for(j=1;;++j){
while(qp(j,m,n)!=1)++j;
for(i=1;i<=t&&qp(j,m/fc[i],n)!=1;++i);
if(i>t)break;
}
for(t=j,i=1,s=0;i<=m;++i,t=t*1ll*j%n)if(!p[i])q[t]=1,++s;else p[i]=0;
wt(s),putchar(10);
for(i=1,j=0;i<n;++i){
if(q[i]){
q[i]=0,++j;
if(j==d)j=0,wt(i),putchar(32);
}
}
putchar(10);
}
return 0;
}