基础回顾--素数筛,欧拉函数

欧拉筛法:

  直接判断素数耗时,换个角度标记非素数,那么没有被标记的就是素数。

  关键点:

  1. 除2之外的偶数必然不是素数,所以只需要遍历奇数
  2. 寻找0-N范围中的素数时,遍历只需要从 2-->sqrt(N+0.5),因为sqrt(N+0.5)之后的数必然在第二层的循环中标记过。
  3. 二层循环的意思:一层循环找到了素数prime,则要将prime的所有倍数都筛去。注意从prime*prime开始筛,因<prime*prime的数必然能被之后找到的prime的倍数筛去。
const int maxn = 10004;
bool vis[maxn];
int prime[maxn], cnt;

void sort_prime() {
  /* 细节注意,偶数的特例2是素数 */ prime[cnt
++] = 2; int m = (int) sqrt(maxn + 0.5); for(int i=3; i<m; i+=2) { if(!vis[i]) { prime[cnt++] = i; for(int j=i*i; j<maxn; j+=i) { vis[j] = true; } } }
  for(int i=(m&1)? m:m+1; i<maxn; i+=2)
        if(!vis[i]) prime[cnt++] = i;
return; }

 

欧拉函数:

  求解所有<=n且与n互素的数的总数,特别的 phi(1) = 1。 (phi其实是数学符号的谐音~)

  根据性质 phi(n) = n*(1-1/p1)*(1-1p2)...*(1-1/pk),pi是n的所有素因子。性质的公式进行变行--> phi(n) = n ∏ [ (pi-1)/pi ] --> 每一步看phi = n,phi = phi / pi * (pi-1)先除后乘防止溢出-->phi = phi - phi/pi -- > phi -= phi/pi

int phi(int N) {
    int tmp = N, n = N;
    for(int i=0; i<cnt && prime[i]<=n; ++i) {
        if(n%prime[i] == 0) {
            tmp -= tmp/prime[i]; //欧拉函数性质推导出的式子
            while(n%prime[i] == 0) // 去掉prime[i]因子
                n /= prime[i];
        }
    }

    //若n != 1,则必然还剩下一个素数没有用
    if(n != 1) tmp -= tmp/n;
    return tmp;
}
posted @ 2019-08-25 21:00  Bankarian  阅读(230)  评论(0编辑  收藏  举报