51nod——1135 原根 (数论)

题目链接

知识点:
1.阶:a和模m互质,使a^d≡1(mod m)成立的最小正整数d称为a对模m的阶(指数)
   例如:
  2^2≡1(mod3),2对模3的阶为2;
  2^3≡1(mod7),2对模7的阶为3;
2.欧拉函数φ(m):在[1,m)的区间内与m互质的数的个数。可见前一篇blog
3.设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原根。

求模素数p的原根a的方法:

对质数 p, φ(p) = p-1, 这题就是要找最小的a使得 a^(p-1)%p = 1 成立(根据费马小定理,该式一定成立,且a可取大于 1 的任意整数),所以只需要验证没有比 p-1 小的数 k 令 a^k%p = 1 。

而 k 不需要全部枚举 ,只需枚举 p-1 除去1和它本身的质因子即可。(如果x为p-1的质因子,且a^x%p = 1,那么x的倍数nx显然也满足a^nx%p = 1 ,所以没必要考虑了。反之同理。)

所以重点就到回到了找质因子上,1e9,还是筛。

参考了很多dalao的博客,但链接没记下来,不好意思。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxn 50000
 5 using namespace std;
 6 typedef long long ll;
 7 int prime [maxn];//存素数
 8 int ppri [maxn];//存p-1的质因子
 9 void getprime(){//打表
10     int cnt = 0;
11     memset(prime,0,sizeof(prime));
12     for(int i=2;i<maxn;i++){
13         if(!prime[i]) prime[++cnt]=i;//如果没被标记过,就是质数
14         for(int j=i;j<maxn;j+=i) prime[j] = 1;//此质数的倍数都标记为1
15     }
16 }
17 ll pow(ll x,ll n,ll mod){//快速幂
18     ll res=1;
19     while(n>0){
20         if(n%2) res=res*x%mod;
21         x=x*x%mod;
22         n/=2;
23     }
24     return res;
25 }
26 
27 int divide(int n){//分解n的质因子
28     int cnt=0;
29     for(int i = 1; prime[i] * prime[i] <= n; ++i){
30         if(n % prime[i] == 0)  ppri[++cnt]=prime[i];
31         while(n % prime[i] == 0)  n/=prime[i];
32     }
33     return cnt;
34 }
35 
36 int main(){
37     int p,a,t,flag,cnt;
38     cin>>p;
39     getprime();
40     cnt=divide(p-1);//p-1 的质因子个数
41     for(a = 2; a <= p - 1; ++a){//a 从 2 到 p-1 枚举
42         flag=1;
43         for(int i=1; i <= cnt; ++i){
44             t = (p - 1) / ppri[i];
45             if(pow(a, t, p)==1){
46                 flag=0;
47                 break;
48             }
49         }
50         if(flag){
51             cout<<a<<endl;
52             break;
53         }
54     }
55     return 0;
56 }
View Code

猜你喜欢

转载自www.cnblogs.com/noobimp/p/10296364.html