题目:
笔记:
原根有诸多美丽的性质:
(1)原根具有和DFT中单位根相似的性质,于是就能在模p意义下进行快速数论变换 (NTT)
(2)若g为p的原根,那么在[0,p]总能找到一个x使得g^x = a (mod p)
在离散数学中,若 g^x = a (mod p),则:
知道这个有什么用呢?对于一个数b,我们可以将其以离散对数的形式表示成x,(根据性质2,x一定可以通过BSGS算法找到),那么我们就能进行下面的运算:
乘法变加法,幂变乘法;假设等式右边的值等于 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;
}