欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

求质数的原根

程序员文章站 2022-07-09 11:51:17
...
#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
int P, cnt, pcnt, p[N], pr[N];
bool np[N];
typedef long long ll;
int gcd(int a, int b) { return b?gcd(b, a%b):a; }
int ipow(int a, int b) { int x=1; for(; b; b>>=1, a=(ll)a*a%P) if(b&1) x=(ll)x*a%P; return x; }
bool check(int d) {
	if(gcd(d, P)!=1) return 0;
	for(int i=1; i<=cnt; ++i) if(ipow(d, (P-1)/pr[i])==1) return 0;
	return 1;
}
void init() {
	for(int i=2; i<N; ++i) {
		if(!np[i]) p[++pcnt]=i;
		for(int j=1; j<=pcnt; ++j) {
			int t=i*p[j]; if(t>=N) break; np[t]=1;
			if(i%p[j]==0) break;
		}
	}
}
void get() {
	int temp=P-1;
	for(int i=1; i<=pcnt && p[i]*p[i]<=temp; ++i) if(temp%p[i]==0) { while(temp%p[i]==0) temp/=p[i]; pr[++cnt]=p[i]; }
	if(temp>1) pr[++cnt]=temp;
}
int main() {
	scanf("%d", &P);
	init();
	get();
	for(int i=2; i<P; ++i) if(check(i)) { printf("%d\n", i); break; }
	return 0;
}

  

如果$(a, m)=1$,那么容易得到$\delta_{m} (a) | \varphi(m)$,因此我们只需要检测$m$的约数即可,可是复杂度很高= =。

更特殊的,假如$m$是质数,那么我们只需要检测$\frac{\varphi(m)}{p_1}, \frac{\varphi(m)}{p_2}, \cdots, \frac{\varphi(m)}{p_k}$($p_i$表示$\varphi(m)$的不同的质因子)即可。

证明:

如果检测出来时,显然$a$不是原根。否则,我们没有检测出来,即$a$不是$m$的原根,令$d<\varphi(a)$使得$a^d \equiv 1 \pmod{m}$

因为$d<\varphi(m)$,所以$(d, \varphi(m)) < \varphi(m)$。

而又因为$(d, \varphi(m)) | \varphi(m)$, 所以$(d, \varphi(m))$必整除$\frac{\varphi(m)}{p_1}, \frac{\varphi(m)}{p_2}, \cdots, \frac{\varphi(m)}{p_k}$中至少一个,令其中一个为$\frac{\varphi(m)}{p_i}$。

由于存在$x, y$使得$dx+\varphi(m)y = (d, \varphi(m))$,所以$a^{(d, \varphi(m))} \equiv (a^d)^x (a^{\varphi(m)})^y \equiv 1 \pmod{m}$。

所以$a^{\frac{\varphi(m)}{p_i}} = (a^{(d, \varphi(m))})^{t} \equiv 1 \pmod{m}$。

与我们没有检测出来的假设矛盾。

故结论得证。

由于质因数分解出来很小,故复杂度我们可以认为是$O(nlog^2n)$,而又因为质数的原根都非常小= =所以...整体来看就是一个常数!