转自:http://blog.csdn.net/dream_you_to_life/article/details/43883367 作者:Sky丶Memory

1.一个数是否为质数的判定.

质数,只有1和其本身才是其约数,所以我们判定一个数是否为质数,只需要判定2~(N - 1)中是否存在其约数即可,此种方法的时间复杂度为O(N),随着N的增加,效率依然很慢。这里有个O()的方法:对于一个合数,其必用一个约数(除1外)小于等于其平方根(可用反证法证明),所以我们只需要判断2~之间的数即可.

 bool is_prime(int num)
{
const int border = sqrt(num);
for (int i = ; i <= border; ++i)
if (num % i == )
return false;
return != num;
}

2.一个数的质因数分解

对于一个数N的质因数分解,简单一点的方法通过枚举2~N之间的每个数字,如果N值能整除当前枚举的数,则将N值除尽,重复上面的步骤,直到结束.我们可以看出此种方法的时间复杂度为O(N),而我们通过上面介绍的方法,可以将时间复杂度降为O(),原理与判定一个数是否为质数是一样的.

 map<int, int> factor(int num)
{
map<int, int> ans;
const int border = sqrt(num);
for (int i = ; i <= border; ++i)
while (num % i == )
++ans[i], num /= i;
if (num > )
ans[num] = ;
return ans;
}   

3.欧拉函数

在数论中,对正整数n,欧拉函数是小于或者等于n的数中与n互质的数的个数.假设n的唯一分解式为,根据容斥原理可知

对于{p1,p2,....,pk}的任意子集S,“不与其中任何一个互述素”的元素个数为。不过这一项的前面是加号还是减号呢?取决于S中元素的个数-———奇数个数就是"减号”,偶数个数就是“加号”,如果对这个地方有疑问的,可以参考下组合数学容斥原理的章节.

现在我们得到了计算欧拉函数的公式,不过这样计算起来非常麻烦。如果根据公式直接计算,最坏情况下需要计算项的多项式。不过这点倒不用我们担心,前人已经在此公式上面已经做了相应的研究,这里直接给出公式的变形,上述公式可以变形成如下的公式:

从而我们计算某个数的欧拉函数,只需要O(K)的计算时间,在刚才原始的基础上大大提高了效率。如果题目中没有给出唯一分解式,我们可以根据第二个小节的做法,在的时间复杂度解决这个问题.

 int euler(int n)
{
const int border = sqrt(n);
int cnt = n;
for (int i = ; i <= border; ++i)
{
if (n % i == )
{
cnt = cnt / i * (i - );
while (n % i == )
n /= i;
}
}
if (n > )
cnt = cnt / n * (n - );
return cnt;
}
 

上面介绍了一些关于素数和欧拉函数的小知识点,那现在进入主题——如何在O(N)的时间复杂度内求出某段范围的素数表.在ACM比赛中,有些题目往往需要求出某段范围内素数,而此时如何高效的求出素数表就显得尤为重要。关于素数表的求法,比较出名的是埃氏素数筛选法。其基本原理是每找到一个素数,将其倍数的数从素数表中删除,不断重复此过程,最终表中所剩数据全部为素数。下面的gif图片展示了该方法的相应步骤:

O(N)的素数筛选法和欧拉函数

埃氏素数筛选法的写法有多种版本,其时间复杂度为,这里给出一份实现代码.

 const int N = 1e+ + ;
bool prime[N];
void init_prime_table(int n)
{
const int border = sqrt(n);
memset(prime, true, sizeof(prime));
prime[] = prime[] = false;
for (int i = ; i <= border; ++i)
{
if (!prime[i])
continue;
//此处j值需要注意溢出的bug
for (long long j = i * i; j <= n; j += i)
prime[j] = false;
}
}

一般情况下,对于大部分的题目上面的写法已经够用了.然而,有人将上述的方法优化到了,效率虽然没有很大数量级的提升,不过,思想还是值得学习的.学过数学知识的人大都知道,对于一个正整数,如果其为合数,那么该数的质因数分解形式是唯一的。假设一个合数n的质因数分解形式为:

现定义:对于某个范围内的任意合数,只能由其最小的质因子将其从表中删除。我们很容易得出该算法的时间复杂度为线性的,为什么呢?因为一个合数的质因数分解式是唯一的,而且我们定义了合数只能由最小质因子将其从表中删除,所以每个合数只进行了一次删除操作(需要注意的是:埃氏素数筛选法中合数可能被多个质数删除,比如12,18等合数).现在原始的问题转换为怎么将合数由其最小的质因子删除?我们考查任何一个数n,假设其最小质因子为m,那么小于等于m的质数与n相乘,会得到一个更大的合数,且其最小质因数为与n相乘的那个质数,而该合数可以直接从表中删除,因为其刚好满足之前的合数删除的定义,所以我们需要维护一个表用来记录已经找到了的质数,然后根据刚才叙述的步骤执行,就能将埃氏素数筛选法的时间复杂度降为.

 const int N = 1e+ + ;
bool prime[N];
int rec[N], cnt;
void init_prime_table(int n)
{
cnt = ;
memset(prime, true, sizeof(prime));
prime[] = prime[] = false;
for (int i = ; i <= n; ++i)
{
if (prime[i])
rec[cnt++] = i;
//此处边界判断为rec[j] <= n / i,如果写成i * rec[j] <= n,需要确保i * rec[j]不会溢出int
for (int j = ; j < cnt && rec[j] <= n / i; ++j)
{
prime[i * rec[j]] = false;
if (i % rec[j] == )
break;
}
}
}

同样的,通过此种方法,我们可以在线性的时间生成某段范围的欧拉函数表,原理与上述类似,这里就不做过多的解释了。

(转载)O(N)的素数筛选法和欧拉函数的更多相关文章

  1. O(n)求素数,求欧拉函数,求莫比乌斯函数,求对mod的逆元,各种求

    筛素数 void shai() { no[1]=true;no[0]=true; for(int i=2;i<=r;i++) { if(!no[i]) p[++p[0]]=i; int j=1, ...

  2. 【数论】【筛法求素数】【欧拉函数】bzoj2818 Gcd

    gcd(x,y)(1<=x,y<=n)为素数(暂且把(x,y)和(y,x)算一种) 的个数 <=> gcd(x/k,y/k)=1,k是x的质因数 的个数 <=> Σ ...

  3. UVA10200-Prime Time/HDU2161-Primes,例题讲解,牛逼的费马小定理和欧拉函数判素数。

                                                    10200 - Prime Time 此题极坑(本菜太弱),鉴定完毕,9遍过. 题意:很简单的求一个区间 ...

  4. 洛谷UVA12995 Farey Sequence(欧拉函数,线性筛)

    洛谷题目传送门 分数其实就是一个幌子,实际上就是求互质数对的个数(除开一个特例\((1,1)\)).因为保证了\(a<b\),所以我们把要求的东西拆开看,不就是\(\sum_{i=2}^n\ph ...

  5. A - Bi-shoe and Phi-shoe 欧拉函数

    /** 题目:A - Bi-shoe and Phi-shoe 链接:https://vjudge.net/contest/154246#problem/A 题意:每一个数都有一个得分,它的得分就是, ...

  6. poj 3090 &amp;&amp; poj 2478(法雷级数,欧拉函数)

    http://poj.org/problem?id=3090 法雷级数 法雷级数的递推公式非常easy:f[1] = 2; f[i] = f[i-1]+phi[i]. 该题是法雷级数的变形吧,答案是2 ...

  7. 转载:Candy? 在线性时间内求出素数与欧拉函数

    转载自:http://www.cnblogs.com/candy99/p/6200660.html 2818: Gcd Time Limit: 10 Sec  Memory Limit: 256 MB ...

  8. 素数的线性筛 && 欧拉函数

    O(n) 筛选素数 #include<bits/stdc++.h> using namespace std; const int M = 1e6 + 10 ; int mindiv[M] ...

  9. poj 2478 Farey Sequence(欧拉函数是基于寻求筛法素数)

    http://poj.org/problem?id=2478 求欧拉函数的模板. 初涉欧拉函数,先学一学它主要的性质. 1.欧拉函数是求小于n且和n互质(包含1)的正整数的个数. 记为φ(n). 2. ...

随机推荐

  1. Ubuntu 18 安装 wps

    本来有三种方法 1. 软件中心 安装最简单 2. 命令行snap 安装 如果没有安装snap 先安装 sudo apt install snapd 然后安装wps sudo snap install ...

  2. [hdu4035] Maze【概率dp 数学期望】

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4035 真的是一道好题,题解比较麻烦,我自己在纸上写了好大一块草稿才搞出来,不用公式编辑器的话就很难看清楚 ...

  3. Fools and Roads CodeForces - 191C

    Fools and Roads CodeForces - 191C 题意:给出一棵n个节点的树,还有树上的k条简单路径(用路径的两个端点u和v表示),对于树上每一条边,求出其被多少条简单路径经过. 方 ...

  4. CalService

    package org.crazyit.cal; import java.math.BigDecimal; /** * 计算业务类 * * @author yangenxiong yangenxion ...

  5. GOTO语句以及GOTO机制的模式实现

    goto语句提供了方法内部的任意跳转,它在特殊场景下被应用. 而假设一个对象执行一个方法后,我们期望其余任何对象都可以捕获它,然后自己执行某些操作,那么可以怎么实现呢 class 皇宫 { void ...

  6. 转-iOS 动画总结----UIView动画

    来自:http://blog.csdn.net/huifeidexin_1/article/details/7597868/ 1.概述 UIKit直接将动画集成到UIView类中,实现简单动画的创建过 ...

  7. Codeforces Round #230 (Div. 1)

    A: 题意:给你一个半径为n的圆 求最少阻塞多少个点 才能使所以圆内及圆上的点 都不与外边的点相连  相连是距离为1 只算整数点 这题定住x,y依次递减 判断一下是否4-connect 这个意思就是 ...

  8. 分享一款强大的图片查看器插件,手机PC 通吃,功能超级齐全!

    一款强大的图片查看器插件,手机PC 通吃,功能超级齐全! 地址:http://photoswipe.com/

  9. .NET框架概述

    .NET战略目标: 任何时候(when),任何地方(where),使用任何工具(what)都能通过.NET的服务获得网络上的任何信息. .NET优势: 1.提供了一个面向对象的编程环境,完全支持面向对 ...

  10. vue组件中—bus总线事件回调函数多次执行的问题

    在利用vue组件进行事件监听时发现,如果对N个vue组件实例的bus总线绑定同一事件的回调函数,触发任意组件的对应事件,回调函数至少会被执行N次,这是为什么呢? 为此,调研了普通对象的事件绑定和触发实 ...