【目录】
一、素数筛
1.素数判断
2.素数普通筛
3.素数线性筛
二、欧拉函数筛
三、莫比乌斯函数筛
【素数筛】
1.直接判定质数
bool judgePrime( int num ) { if(num < 2 ) return 0; int tmp =sqrt( num ); for(int i= 2; i <=tmp; i++) if(num % i == 0) return 0 ; return 1 ; }
2.素数普通筛
const int maxn = 1e7; bool isPrime[maxn+10]; int prime[maxn+10]; int count = 0; //普通筛法 void getPrime(){ memset(isPrime, 1, sizeof isPrime); isPrime[1] = isPrime[0] = 0; //筛出bool数组 for(int i=2; i*i<=maxn; i++){ //如果想在这里直接把素数打入prime数组里那么这里i<maxn if(isPrime[i]){ for(int j=2; j<=maxn/i; j++){ isPrime[i*j] = 0; } } } //根据bool数组把素数打入素数表 ,如果只要判断素数则以下代码可注释 // for(int i=0; i<maxn; i++){ // if(isPrime[i]) // prime[count++] = i; // } }
3.素数线性筛
保证每个素数只会被筛一次
//线性筛法 bool check[maxn + 10]; int prime2[maxn + 10]; int count2 = 0; void getPrime2(){ memset(check, 1, sizeof check); check[0] = check[1] = 0; for(int i=2; i<=maxn; i++){ if(check[i]){ prime2[count2++] = i; } for(int j=0; j<count2; j++){ if(i*prime2[j] > maxn) break; check[i*prime2[j]] = 0; if(i%prime2[j] == 0) break; } } }
小结:当需要频繁地判定素数时需要筛表,否则可以直接进行素数判断。筛表时,如果需要频繁地用素数而不是仅仅需要判定素数,用线性筛,否则用普通筛筛出bool数组即可。
筛表的范围,1e6基本无压力,1e7稍微有点大但能撑得住,1e8筛表速度很慢,1e9无法筛表,时间空间都跟不上。
二、欧拉函数
欧拉函数的定义:
在数论中,对于正整数N,少于或等于N ([1,N]),且与N互质的正整数(包括1)的个数,记作φ(n)。
φ函数的值:
φ(x)=x(1-1/p(1))(1-1/p(2))(1-1/p(3))(1-1/p(4))…..(1-1/p(n)) 其中p(1),p(2)…p(n)为x的所有质因数;
1.直接判断
int Euler(int n){ int ans = n; //这里的n在不断收缩 循环次数上界将越来越小 for(int i=2; i<=n; i++){ if(n % i == 0){ ans = ans - ans/i; } //把该素因子除尽 while(n % i == 0) n = n/i; } return ans; }
2.欧拉函数筛表
筛表不太好理解,可以类比质数筛
(1)先锁定欧拉函数计算方法φ(x)=x(1-1/p(1))(1-1/p(2))(1-1/p(3))(1-1/p(4))…..(1-1/p(n)) 其中p(1),p(2)…p(n)为x的所有质因数;
(2)不妨初始化φ(x)=x
(3)每次遇到素因子的时候就乘上一个 p(i)-1 / p(i),p(i)是x的质因子
#define Max 1000 int euler[Max]; void Init(){ euler[1]=1;
for(int i=2;i<Max;i++) euler[i]=i; //初始化φ(x)=x for(int i=2;i<Max;i++) if(euler[i]==i) //这个欧拉值没有被更新过则需要更新,保证了进行更新时,i一定是素数 for(int j=i;j<Max;j+=i) euler[j]=euler[j]/i*(i-1);//先进行除法是为了防止中间数据的溢出 }
小结:
三、莫比乌斯函数筛
待更新