原根

知识点

  • 定义:由欧拉定理可知,对\(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)\)

  • 性质:

  1. \(a^1,a^2,...,a^{\delta_m(a)}\)\(m\)两两不同余

  2. \(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)\)

  3. \(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\)

  4. \(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)}\)

  5. \(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\)的原根

  • 定理:

  1. 原根判定定理:设\(m\geqslant3,gcd(a,m)=1\),则\(a\)是模\(m\)的原根的充要条件是,对于\(\varphi(m)\)的每个素因数\(p\),都有
    $a^{\frac{\varphi(m)}{p}}\not\equiv1\pmod m $

  2. 原根个数:若一个数\(m\)有原根,则它原根的个数为\(\varphi(\varphi(m))\)

  3. 原根存在定理:
    引理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\)的原根不存在

  4. \(gcd(g,n)\)且(n>0),则\(g\)\(n\)的一个原根的充要条件为\(S=\{g^1,g^2...g^{\varphi(n)}\}\)\(n\)的一组简化剩余系

  5. 若奇素数\(p\)的原根\(g\)满足\(g^{p-1}\not\equiv1\pmod {p^2}\),则对于每一个\(a\geqslant2\),有\(g^{\varphi(p^{a-1})}\not\equiv1\pmod {p^a}\)

  6. \(p\)为素数,\(a\)为整数且\(p\nmid a\),则在一个模\(p\)的完全剩余系中恰有\(\varphi(\delta_p(a))\)个数模\(p\)的阶为\(\delta_p(a)\)

  7. 对于任意整数\(h\)使得\(\delta_p(h)=\delta_p(a)\),定存在\(a^{d_i} (i\in[1,\varphi(\delta_p(a))\cap\mathbb{Z}])\)在模\(p\)意义下与\(h\)同余

  8. \(p\)为整数且有一个原根\(g\),则\(p\)恰有\(\varphi(\varphi(p))\)个在模\(p\)意义下不同余的原根,它们由集合\(S=\{g^i|1\leqslant i\leqslant\varphi(p),gcd(p,i)=1\}\)中的数给出

求原根

  1. 线性筛预处理所有质数和有原根的数,\(O(n)\)
  2. \(\varphi(n)\) 分解因数,由于质数已经筛出,复杂度 $O(n^{0.5}/\log n) $
  3. 快速幂求出最小原根,复杂度大概是 \(O(n^{0.25}\log n\log\log n)\)
  4. 通过最小原根求出所有原根,需要进行 \(\varphi(n)\) 次求最大公约数, \(O(n\log n)\)
  5. 排序,从小到大输出,$ 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;
}

edit

posted @ 2023-02-11 14:30  雨夜风月  阅读(44)  评论(0编辑  收藏  举报