转自: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. Canvas 入门案例

    五.  Canvas 入门案例 1.  canvas 圆形绘制 <!DOCTYPE html> <html lang="en"> <head> ...

  2. BZOJ2006 超级钢琴

    Description ​ 给定一个长度为n的区间,询问前k大的区间和,区间长度\(\in [L, R]\). $ n, k <= 500000$ Solution ​ 首先求前缀和.把一个区间 ...

  3. 【BZOJ3514】Codechef MARCH14 GERALD07加强版(LCT_主席树)

    题目: BZOJ3514 分析: 看到这题真的是一脸懵逼无从下手,只好膜题解.看到「森林的联通块数 = 点数 - 边数」这一句话就立刻什么都会了 QAQ . 这题最重要的就是意识到上面那个式子(正确性 ...

  4. 一步一步学习GTK

    完成课设,偶然碰到GTK,索性学习一遍 转载自ikoDotA の BLOG (一).一步一步学GTK+之开篇 一.什么是GTK+ GTK+ 是一种函数库是用来帮助制作图形交互界面的.整个函数库都是由C ...

  5. Ubuntu编译安装Apache

    第一步:编译安装依赖包apr,apr-util和pcre ./configure --prefix= make && make install 第二步:编译安装Apache ./con ...

  6. Xml学习笔记(1)

    不同的xml文档构可能要用到不同的方法进行解析这里用到的是例如<student name="张三" id="1" sex="男"/&g ...

  7. JDK常用类解读--StringBuffer、StringBuilder

    上一篇博客讲到String对象一旦被创建该内容就不能被修改了如: String s = "hello world"; s.substring(6); s.replace(" ...

  8. ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第二天(非原创)

    文章大纲 一.课程介绍二.整合淘淘商城ssm项目三.Mybatis分页插件PageHelper使用四.整合测试五.项目源码与资料下载六.参考文章   一.课程介绍 一共14天课程(1)第一天:电商行业 ...

  9. Tomcat源码分析----eclipse中搭建源码环境

    前提:JDK,至少1.7,ant,要设置ANT_HOME环境变量,需要再classpath中增加ant的lib目录,在path变量中增加ant的bin目录 1.官网下载tomcat源码包:apache ...

  10. 锐动SDK置于社区沙龙

    北京锐动天地信息技术有限公司成立于2007年9月.多年来一直专注于音视频领域核心技术的研发, 拥有Windows.iOS.Android全平台自主知识产权的领先技术产品. 2011年获得新浪战略投资, ...