主要參考這里:
http://www.cnblogs.com/autsky-jadek/p/7496178.html
https://blog.csdn.net/a27038/article/details/77203892
定義:
定義\(a\)模\(m\)的階為,使得\(a^t\equiv1\ (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}}\not\equiv 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^t\equiv a\ (mod\ p)(1\leq t\leq 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\n",Find_root(read()));
return 0;
}
另一道例題:BZOJ.3992.[SDOI2015]序列統計。