原根 学习笔记
主要参考这里:
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]序列统计。
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------