xtuoj 原根
题目
思路
快速幂
这里可以参考快速幂(c++,超级详细)-CSDN博客这篇文章,举个例子计算a^5,将指数5转为二进制为101,所以a^5=a*a^4,按照代码首先是res=1,这里是用来存最后计算的结果的,初始化为1,是因为任何一个数乘以1等于它本身,再然后是while(b),这个循环条件是b,二进制中非0则1,只要是1就会满足条件,就会进入while循环,循环内部首先是if(b&1),由位运算的知识,0&1=0,0&0=0,1&0=0,1&1=0,这是按位与运算,只有二者都为1时结果为1,任意出现0则结果为0,1的二进制数只有末尾为1,其余位为0,所以不管b其余位是什么,按位与的结果只会为0,所以我们只要考虑b末位,当b的末尾为1时,满足if语句条件,执行res*=a,然后把b的末位抹去,即b>>1,即b右移一位,然后a也要翻倍,因为我们是考虑a^1,a^2,a^4...,如此循环,直到b为0时结束,我们就计算出a^b了,时间复杂度也从O(n)优化到O(logn),因为每次我们不是一个一个的去乘了,而是每次都会翻倍,是指数式的,所以时间复杂度也就会变成O(logn)
我们这个题目使用的是带余数的快速幂,上述我解释了不带余数版本,带余数版本类似,这里不再赘述,注意要在过程中每次都取余,而不是计算出a^b以后再取余
分解质因数
将temp分解成质因数的乘积,并记录每个质因数,采用试除法,从2开始,质因数最大为≤ √(原始temp),用factors数组记录质因数,用while循环将当前的质因数全部除尽,重复操作,最后剩下来的temp如果大于1,那么它本身也是一个质因数,这是由于质数判定定理,如果一个数 n > 1
且不能被任何 ≤ √n
的质数整除,那么 n
本身一定是质数
原根
参考文章原根-快速求解一个数的原根_求原根-CSDN博客,但是这个博主写的程序有点问题哈,主要看下面这部分吧,证明要用到欧拉函数和裴蜀定理
代码
#include<stdio.h>
#include<stdbool.h>
#define ll long longll fast_pow(ll a, ll b, ll p){ll res=1;while(b>0){if(b&1) res=(res*a)%p;a=(a*a)%p;b>>=1;}return res;
}bool is_pri_root(ll p){int cnt=0;ll factors[100];ll temp=p-1;//分解p-1的质因数for(ll i=2;i<=temp/i;i++){if(temp%i==0){factors[cnt++]=i;while(temp%i==0){temp/=i;}}}if(temp>1) factors[cnt++]=temp;//检查2^((p-1)/q)%p是否为1,为1,则不是原根,q为质因数for(int i=0;i<cnt;i++){ll ex=(p-1)/factors[i];if(fast_pow(2,ex,p)==1) return false;}return true;
}int main(){ll p;while(scanf("%lld",&p)!=EOF){if(is_pri_root(p)) printf("Yes\n");else printf("No\n");}return 0;
}