HDU---4992:Primitive Roots【原根模板】

题目:

HDU----4992:Primitive Roots

笔记:

原根有诸多美丽的性质:

(1)原根具有和DFT中单位根相似的性质,于是就能在模p意义下进行快速数论变换 (NTT)

(2)若g为p的原根,那么在[0,p]总能找到一个x使得g^x = a (mod p)

在离散数学中,若 g^x = a (mod p),则:

Ind_ga = x~(mod~\varphi(p))

知道这个有什么用呢?对于一个数b,我们可以将其以离散对数的形式表示成x,(根据性质2,x一定可以通过BSGS算法找到),那么我们就能进行下面的运算:

Ind_ga^b = bInd_ga~(mod~\varphi(p))

Ind_gab = Ind_ga+Ind_gb~(mod~\varphi(p))

乘法变加法,幂变乘法;假设等式右边的值等于 x,最后再通过g^x还原回去即可得到a^b或a*b的值;

两道离散对数的例题:

ZOJ---3998:Yet Another Data Structure Problem

CodeFores---1182E:Product Oriented Recurrence

网上关于原根的求解挺多的,这里就只存个板子

代码:

#include <bits/stdc++.h>

#define sz(x) (int)(x).size()
using namespace std;
typedef long long LL;
const int maxn = 1e6+16;
int prime[maxn],phi[maxn],cnt;
void init(){
    phi[1] = 1;
    for(int i = 2;i < maxn; ++i){
        if(!phi[i]) prime[cnt++] = i,phi[i] = i-1;
        for(int j = 0;j<cnt&&1ll*prime[j]*i<maxn; ++j){
            if(i%prime[j] == 0){
                phi[i*prime[j]] = phi[i]*prime[j];
                break;
            }
            else phi[i*prime[j]] = phi[i]*phi[prime[j]];
        }
    }
}
LL qpow(LL a,LL x,LL mod){
    LL res = 1;
    while(x){
        if(x&1) res = res*a%mod;
        a = a*a % mod;
        x >>= 1;
    }
    return res;
}
vector<int> PrimeFactor(int x){          //分解质因子
    vector<int> fac;
    for(int i = 0;i<cnt&&1LL*prime[i]*prime[i]<=x;++i){
        if(x%prime[i] == 0){
            fac.push_back(prime[i]);
            while(x%prime[i] == 0) x /= prime[i];
        }
    }
    if(x > 1) fac.push_back(x);
    return fac;
}
bool checkroot(int x){                      //判断是否存在原根
    if(x==2||x==4) return true;
    if(x%4 == 0) return false;
    if(x%2 == 0) x /= 2; 
    for(int i = 0;i<cnt&&1ll*prime[i]*prime[i]<=x;++i){
       if(x%prime[i] == 0){
          while(x%prime[i] == 0) x /= prime[i];
          return x == 1;
       }
    }
    return true;
}
int PrimitiveRoot(int x){                  //得到x最小的原根
    if(x==2 || x==4) return x-1;
    vector<int> fac = PrimeFactor(phi[x]);
    for(int i = 2;i < x; ++i){
        bool flag = true;
        for(int j = 0;j<sz(fac)&&flag;++j){
            if(qpow(i,phi[x]/fac[j],x) == 1) flag = false;
        }
        if(flag&&qpow(i,phi[x],x)==1) return i;
    }
}
void solve(int x){                         //得到全部的原根
    if(!checkroot(x)) {puts("-1"); return;}
    PrimeFactor(phi[x]); int g = PrimitiveRoot(x);
    vector<int> ans; ans.push_back(g);
    for(int i = 2;i < phi[x]; ++i){
        if(__gcd(i,phi[x])==1) ans.push_back(qpow(g,i,x));
    }
    sort(ans.begin(),ans.end());
    for(int i = 0;i < sz(ans)-1; ++i) cout << ans[i] << " ";
    cout << ans[sz(ans)-1] << '\n';
}
int main(){
    int n; init();
    while(cin >> n) solve(n);
    return 0;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值