主要参考这里:
http://www.cnblogs.com/autsky-jadek/p/7496178.html
https://blog.csdn.net/a27038/article/details/77203892
定义:
定义(a)模(m)的阶为,使得(a^tequiv1 (mod m))成立的最小正整数(t)((a,m)互质)。用(delta_m(a))表示。
当(a,m)互质且(varphi(m)=delta_m(a))时,则称(a)为模(m)的一个原根。
模(m)存在原根的充要条件:(m=2,4,p^a,2p^a),其中(p)是奇素数。
若模一个数(p)存在原根,那么其原根个数为(varphi(varphi(p)))。
求模(P)的原根:
若(P)是质数,将(P-1)质因数分解,即令(P-1=prod_{i=1}^kp_i^{a_i})。
若对于(i=1,2,...,k),都有$$g^{frac{P-1}{p_i}}
otequiv 1 (mod P)$$
那么(g)就是(P)的一个原根((g)可以直接枚举,通常原根不会太大)。
若(P)是合数,将(P-1)换成(varphi(P))即可。
性质:
若(g)是模(p)的一个原根,则(g,g^2,...,g^{varphi(p)})在模(p)意义下两两不同,且恰好是小于(p)且与(p)互质的(varphi(p))个正整数的一个排列。
下面考虑(p)是质数的情况(合数一样吗我不太清楚啊...)
若(g^tequiv a (mod p)(1leq tleq p-1)),则相应的指数(t)被称为以(g)为底的(a)模(p)的指标。若(p,g)已知,则记指标为(I(a)),即(I(a)=t)。
那么有指标法则:
这样就可以将乘法化为加法,与连续数学中的对数很相似,因此指标也叫做离散对数。
下面是一道求原根的模板题:
51Nod.1135.[模板]原根
//46ms 1,880KB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1e6+5;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline int FP(int x,int k,int mod)
{
int t=1;
for(; k; k>>=1,x=1ll*x*x%mod)
if(k&1) t=1ll*t*x%mod;
return t;
}
int Find_root(int P)
{
static int p[N];
int cnt=0,x=P-1;
for(int i=2; i*i<=x; ++i)
if(!(x%i))
{
p[++cnt]=i;
while(!(x%i)) x/=i;
}
if(x!=1) p[++cnt]=x;
for(int x=2; ; ++x)
{
bool ok=1;
for(int i=1; i<=cnt; ++i) if(FP(x,(P-1)/p[i],P)==1) {ok=0; break;}
if(ok) return x;
}
return -1;
}
int main()
{
printf("%d
",Find_root(read()));
return 0;
}
另一道例题:BZOJ.3992.[SDOI2015]序列统计。