原根

前置知识

欧拉函数

若正整数m,a,满足\((a,m)=1\),则\(a^{\phi(m)}\equiv 1(mod\: m)\)

若正整数m,a,满足\((a,m)=1\),则使得\(a^n\equiv 1(mod \: m)\)的最小正整数n称为a模m的阶,记为\(\delta_m(a)\)

阶的性质

假设\((a,m)=1\)\(\delta=\delta_m(a)\),则

  • \(a^0,a^1,···,a^{\delta-1}\)在模m意义下两两不同
  • \(a^{\gamma}\equiv a^{\gamma'}(mod\: m)\Leftarrow\Rightarrow \gamma\equiv \gamma' (mod \: \delta)\)
  • \(\delta | \phi(m)\)

原根

\(\delta_m(a)=\phi(m)\),则称a为m的一个原根

原根的存在定理

只有模\(2,4,p^a,2p^a\)存在原根(p是奇质数)

原根的判定定理

\(m>1\),g为正整数且\((g,m)=1\)。则g是m的原根当且仅当对于任意\(\phi(m)\)的质因子\(q_i\)\(g^{\frac{\phi(m)}{q_i}}\not\equiv 1(mod \: m)\)

具体实现求原根

首先找到n的最小原根g,则n 的所有原根可以表示为\(g^k\:mod\: n 且gcd(k,\phi(n))=1\)
我们在得到n的最小原根g后便可在\(O(\phi(n)log\phi(n))\)的时间复杂度内得到n的所有原根。

点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<map>
#define ll long long 
using namespace std;
const int maxn=1e6+10101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
int tot,is[maxn],prime[maxn],phi[maxn];
void getprime(){
    phi[1]=1;
    for(int i=2;i<=1000000;i++){
        if(!is[i])prime[++tot]=i,phi[i]=i-1;
        for(int j=1;j<=tot && prime[j]<=1000000/i;j++){
            is[prime[j]*i]=1;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}
ll power(ll x,ll y,ll mod){
    ll ans=1;
    while(y){
        if(y&1)ans=ans*x%mod;
        y>>=1;x=x*x%mod;
    }
    return ans%mod;
}
int gcd(int x,int y){
    if(y==0)return x;
    return gcd(y,x%y);
}
int t,n,d;
int main(){
    getprime();t=read();
    while(t--){
        n=read();d=read();
        vector<int>a,ans;
        for(int i=1;i<=tot && prime[i]<=n;i++){
            if(phi[n]%prime[i]==0){a.push_back(prime[i]);}
        }
        int minn=-1;
        for(int i=1;i<n;i++){
            if(gcd(i,n)!=1)continue;
            bool fa=true;
            for(auto j:a){
                if(power(i,phi[n]/j,n)==1){fa=!fa;break;}
            }
            if(fa){minn=i;break;}
        }
        for(int i=1;i<=phi[n] && minn!=-1;i++){
            if(gcd(i,phi[n])==1)ans.push_back(power(minn,i,n));

        }
        sort(ans.begin(),ans.end());
        printf("%lu\n",ans.size());
        for(int i=1;i*d<=ans.size();i++)printf("%d ",ans[i*d-1]);
        printf("\n");
    }
    return 0;
}

指标

对于质数p,假设g是p的一个原根,则\(g^0,g^1,····,g^{p-2}\)在模p意义下是1,2,···,p-1的一个排列。
假设对于\(1\leq x\leq p-1 有 g^c\equiv x (mod \: p)\),则称x的指标为c,记作\(ind(x)=c\)

性质

\(\forall 1\leq x,y<p, ind(xy)\equiv ind(x)+ind(y) (mod \:\phi(p))\)
\(ind(x^c)\equiv c\cdot ind(x) (mod\: \phi(p))\)
类似于log

求指标--baby step giant step (BSGS)

\(g^c\equiv x(mod\: p)\)
\(c=aB-b,当B=\lfloor \sqrt p \rfloor时最优\)
\(g^{aB-b}\equiv x(mod\:p),(0\leq a,b<B)\)
\((g^B)^a\equiv x\cdot g^b (mod \: p)\)
我们可以分别求出当b=0,1,2,····,B-1时的\(x\cdot g^b\)用map存起来
这样分别对于a=0,1,2,···,B-1,直接查找是否存在右边的值等于左边,记录答案即可
例题Discrete Roots题解

posted @ 2022-01-03 16:34  I_N_V  阅读(143)  评论(0编辑  收藏  举报