hdu 4992 Primitive Roots 【求原根模板】

题目链接

大题流程: 判定是否有原根->求出最小原根->利用最小原根找出全部原根

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int maxn=1e6+5;
int prime[maxn+5];
bool check[maxn+5];
int phi[maxn+5];
int num_prime;
void init()
{
    memset(check, false, sizeof(check));
    phi[1]=1;
    for(int i=2; i<=maxn; i++)
    {
        if(!check[i])
        {
            prime[num_prime++]=i;
            phi[i]=i-1;
        }
        for(int j=0; j<num_prime; j++)
        {
            if(i*prime[j]>maxn) break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else
            {
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
}

LL gcd(LL a, LL b)
{
    return b? gcd(b,a%b):a;
}

void get(LL n,vector<LL>& fac)    //对n进行因式分解 
{
    fac.clear();
    for(LL i=2; i*i<=n; i++)
        if(n%i==0)
        {
            fac.push_back(i);
            while(n%i==0) n/=i;
        }
    if(n>1) fac.push_back(n);
}

LL qpow(LL x,LL n,LL mod)        //求x^n%mod
{
    LL ret=1;
    for(; n; n>>=1)
    {
        if(n&1) ret=ret*x%mod;
        x=x*x%mod;
    }
    return ret;
}

vector<LL> fac;
vector<LL> ans;

bool ok(LL x)
{
    if(x%2==0) x/=2;
    if(x%2==0) return false;
    for(int i=0; prime[i]*prime[i]<=x; i++) if(x%prime[i]==0)
        {
            while(x%prime[i]==0) x/=prime[i];
            return x==1;
        }
    return true;
}

LL get_g(LL p)        //得到一个正整数p的最小原根 
{
    for(int i=2; i<p; i++)
    {
        bool flag=false;
        for(LL x:fac)
            if(qpow(i,phi[p]/x,p)==1)
            {
                flag=true;
                break;
            }
        if(!flag&&qpow(i,phi[p],p)==1)  return i;
    }
}

void GetAns(LL g,LL p,vector<LL>& ans)    //由最小原根p,得到某正整数p的全部原根 
{
    ans.clear();
    ans.push_back(g);
    for(int i=2; i<phi[p]; i++)
        if(gcd(i,phi[p])==1) ans.push_back(qpow(g,i,p));
}

int main()
{
    init();
    LL p;
    while(~scanf("%lld",&p))
    {
        if(p==2||p==4)
        {
            printf("%lld
",p-1);
            continue;
        }
        if(!ok(p))        //首先判断是否有原根 
        {
            puts("-1");
            continue;
        }
        get(phi[p],fac);
        LL g=get_g(p);        //定义g为最小原根
        GetAns(g,p,ans);
        sort(ans.begin(),ans.end());
        for(int i=0; i<ans.size(); i++)
            printf("%lld%c",ans[i],i==ans.size()-1? '
':' ');
    }
}
原文地址:https://www.cnblogs.com/Just--Do--It/p/7382593.html