阶:设a,p是整数,a和p互素,那么:使
成立的最小正整数n叫做a模p的阶.
![](https://gss3.bdstatic.com/7Po3dSag_xI4khGkpoWK1HF6hhy/baike/s%3D101/sign=f5465a52d83f8794d7ff4c2ee31a0ead/eac4b74543a98226a8ff92cd8682b9014a90eb1a.jpg)
原根:设m是正整数,a是整数,若a mod m的阶等于φ(m),则称a为模m的一个原根.(其中φ(m)表示m的欧拉函数)
假设一个数g是质数P的原根,那么
的结果两两不同,且有 1<g<P,0<i<P,归根到底就是
当且仅当指数为P-1的时候成立.
![](https://images2018.cnblogs.com/blog/1306234/201808/1306234-20180805160044148-37943296.png)
![](https://images2018.cnblogs.com/blog/1306234/201808/1306234-20180805160626062-1361151483.png)
有了这个上面性质,就可以容易的求出质数P的原根了.
Step1 将P-1进行质因数分解![](https://images2018.cnblogs.com/blog/1306234/201808/1306234-20180805161420378-88198230.png)
![](https://images2018.cnblogs.com/blog/1306234/201808/1306234-20180805161420378-88198230.png)
Step2 枚举i,并判断对于每个i是否都有
(可以应用快速幂)
![](https://images2018.cnblogs.com/blog/1306234/201808/1306234-20180805161139578-1394651233.png)
第一个符合条件的i就是P的最小原根
对于合数,只要将Step2中的p-1替换成φ(p)即可.
这里是代码
#include <cmath> #include <cstdio> #define ll long long #define maxn 1000010 bool vis[maxn]; ll p,prime[maxn],cnt; ll fp(ll x,ll a){ ll ret=1; for(x%=p;a;a>>=1,x=x*x%p) if(a&1) ret=ret*x%p; return ret; } void get_prime(int x){//筛出x以内的素数 for(int i=2;i<=x;i++){ if(!vis[i]) prime[++cnt]=i; for(int j=1;j<=cnt;j++){ if(i*prime[j]>x) break; vis[i*prime[j]]=1; if(i%prime[j]==0) break; } } } bool check(ll x){//检查x是否是p的原根 ll t=sqrt(x)+10; for(int i=1;prime[i]<=t;i++){ if((p-1)%prime[i]==0&&fp(x,(p-1)/prime[i])%p==1) return 0; } return 1; } int main(){ scanf("%lld",&p); get_prime(maxn); for(int i=1;i<=1000000;i++){ if(check(i)){ printf("%d ",i); return 0; } } }