素数筛

朴素算法

一般来说,可以用试除法判断某一个数是不是素数:

bool isPrime(int n) {
if(n < 2) return false;
for(int i = 2; i < n; i++)
if(n % i == 0) return false;
return true;
}

但其实我们只需要试除到根号n即可,因为对于任意的n,假设存在一个大于根号n的因数,那么肯定存在一个小于根号n的因数与之对应。那么有:

bool isPrime(int n) {
if(n < 2) return false;
int m = sqrt(n + .5);
for(int i = 2; i <= m; i++)
if(n % i == 0) return false;
return true;
}

埃氏筛

但如果我们要求所有小于等于n的数是不是素数呢?这时我们用素数筛法解决。筛法是一种思想,利用之前处理过的信息来更新后面的结果。对于一个大于1的数,它的倍数显然是合数,那么我们可以在遍历到i时,筛去所有i的倍数;当我们遍历到i+1时,只要它还没有被筛去,那它就一定是素数。这就是埃拉托斯特尼筛法,简称埃氏筛

int prime[M];
bool vis[M];
void eratosthenes() {
for (int i = 2; i < M; i++) {
if (!vis[i]) {
prime[++prime[0]] = i;
for (int j = 2 * i; j < M; j += i) {
vis[j] = 1;
}
}
}
}

改进埃氏筛

显然埃氏筛有很多的重复的筛除操作,把朴素算法中的优化引入埃氏筛,我们就可以得到改进的埃氏筛。

int prime[M];
bool vis[M];
void eratosthenes_plus() {
int m = sqrt(M + .5);
for (int i = 2; i <= m; i++) {
if (!vis[i]) {
prime[++prime[0]] = i;
for (int j = i * i; j < M; j += i) {
vis[j] = 1;
}
}
}
}

欧拉筛

虽然改进的埃氏筛复杂度在大多数情况已经可以被接受了,但有时我们需要线性时间判断1~n的所有素数。这时就需要欧拉筛。欧拉筛通过保证每个素数都会被它最小的那个(质)因数筛掉,进而使复杂度达到线性。

int prime[M];
bool vis[M];
void euler() {
for(int i = 2; i < M; i++) {
if(!vis[i]) {
prime[++prime[0]] = i;
}
for(int j = 1; j <= prime[0] && i * prime[j] < M; j++) {
vis[i * prime[j]] = 1;
if(i % prime[j] == 0) {
break;
}
}
}
}

重点就在于if(i % prime[j] == 0)这一句,为什么要在i是第j个素数的倍数时停止筛除呢?

\[\begin{align}
& 当i是prime[j]的倍数时,我们可以把i表示为i=k\times prime[j],k\in N^+。\\
& 对于下一个被筛去的数X,X=i\times prime[j+1]=k\times prime[j]\times prime[j+1],\\
& 显然X还存在一个更小的质因子prime[j],为了符合每个数都被最小的质因数筛去的原则,\\
& 此时应该跳出循环,不用prime[j+1]\times(k\times prime[j])筛去X,而应该在将来,\\
& 用prime[j]\times(k\times prime[j+1])筛去X。
\end{align}
\]

欧拉函数与欧拉定理

欧拉函数

在数论中,对正整数n,欧拉函数φ(n)的值为小于或等于n的正整数中与n互质的数的个数。

例如:φ(8)=4,因为1,3,5,7与8互质。

扩展:在群论中,欧拉函数实际上是模n的同余类构成的乘法群的阶。

欧拉定理

在数论中,欧拉定理为:若gcd(a,n)=1,则:

\[a^{\phi(n)}\equiv 1(mod\space n)
\]

欧拉函数的性质和拉格朗日陪集定理结合构成了欧拉定理的证明。

推广:欧拉降幂公式

\[a^b\equiv a^{b\%\phi(n)+\phi(n)}(mod\space n)
\]

例题:洛谷 5091

性质

基本性质

若n是质数p的k次幂,那么有:

\[\phi(n)=\phi(p^k)=p^k-p^{k-1}=(p-1)p^{k-1}\\
p^{k-1}为1到n中p的倍数,显然这些数与n不互质。
\]

例:

\[\phi(72)=\phi(2^3\times 3^2)=2^{3-1}\times (2-1)\times 3^{2-1}\times (3-1)=24
\]

费马小定理的推广

回顾费马小定理:若p为质数,a为任意正整数,那么:

\[a^p-a可以被p整除。
\]

即:

\[\begin{aligned}
&a^p-a\equiv0(mod\space p)\\
\Leftrightarrow&a^p\equiv a(mod\space p)\\
\Leftrightarrow&a^{p-1}\equiv 1(mod\space p)
\end{aligned}
\]

回到欧拉定理,若p为质数,φ(p)=p-1,那么有:

\[a^{p-1}\equiv 1(mod\space p)
\]

这就是费马小定理。历史上,欧拉首先证出了费马小定理,然后在这个基础上推广得到了欧拉定理。

积性函数

即若m,n互质,那么有φ(mn)=φ(m)φ(n)

推广:小于n的所有与n互质的数的和为n*φ(n)/2。

对任意a>b>0,gcd(a,b)=1,总有gcd(a,a-b)=1。那么对于n,有φ(n)个小于n的数与n互质,设其为x,那么总存在一个n-x也与n互质,两者之和为n,那么一共有φ(n)/2对。这些数的和为n*φ(n)/2。

例:hdu 3501

题意:求比n小的、和n不互质的数的和%1,000,000,007,其中n≤10的9次方。

欧拉函数计算

对于任意正整数n,分解质因数得:

\[n=p_1^{k_1}\times p_2^{k_2}\times ......\times p_m^{k_m}
\]

由:

\[\phi(p^k)=p^k-p^{k-1}=p^k(1-{1\over p})
\]

得:

\[\phi(n)=p_1^{k_1}(1-{1\over p_1})\times p_2^{k_2}(1-{1\over p_2})\times ......\times p_m^{k_m}(1-{1\over p_m})
\]

又:

\[n=\prod_{i=1}^m p_i^{k_i}
\]

所以:

\[\phi(n)=n\times \prod_{i=1}^m (1-{1\over p_i})
\]

代码实现如下:(例题:poj 2407)

// 计算单个欧拉函数值
int euler(int n) {
int ans = n;
// 追求更高效率还可以结合素数表
int m = sqrt(n + .5);
for(int i = 2; i * i <= n; i++) {
if(n % i == 0) {
ans -= ans / i;
while(n % i == 0) n/= i;
}
}
if(n > 1) ans -= ans / n;
return ans;
}

下面是打表写法。

LL euler[N];
void cal_euler() {
euler[1] = 1;
for(int i = 2; i <N; i++) {
if(!euler[i]) {
for(int j = i; j < N; j += i) {
if(!euler[j]) euler[j] = j;
euler[j] -= euler[j] / i;
}
}
}
}

例题:hdu 2824

题意:欧拉前缀和。注意空间限制。

#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 3e6 + 100;
LL euler[N];
void pre() {
euler[1] = 1;
for(int i = 2; i <N; i++) {
if(!euler[i]) {
for(int j = i; j < N; j += i) {
if(!euler[j]) euler[j] = j;
euler[j] = euler[j] / i * (i - 1);
}
}
}
for(int i = 2; i < N; i++) {
euler[i] += euler[i - 1];
}
}
int main() {
pre();
int a, b;
while(cin >> a >> b) {
cout << euler[b] - euler[a - 1] << endl;
}
return 0;
}

积性函数

定义

在数论中,积性函数是指定义在正整数集上的算数函数f(n),且有:f(1)=1;若gcd(a,b)=1,f(ab)=f(a)f(b)。

扩展:完全积性函数:若积性函数f在gcd(a,b)≠1时,仍有f(ab)=f(a)f(b),那么f称为完全积性函数。在数论外的积性函数一般是指完全积性函数。

性质

对n质因分解得:

\[n=\prod^k_{i=1} p_i^{a_i},其中,p_i为分解得到的质因数
\]

那么对于积性函数f,有:

\[f(n)=\prod^k_{i=1}f(p_i^{a_i})
\]

常见的积性函数

欧拉函数、莫比乌斯函数、gcd(n,k)(k固定),约数函数σ(σ(n)为n的约数个数)。约数个数函数σ定义如下:

对于任意正整数n,设其质因分解为:

\[n=p_1^{k_1}\times p_2^{k_2}\times ......\times p_m^{k_m}
\]

那么其因数个数为:

\[N=(k_1+1)\times(k_2+1)\times...\times(k_m+1)
\]

\[即:σ(n)=\prod_{i=1}^m (k_i+1)
\]

Algorithm: Prime & Euler Function & Productive Function的更多相关文章

  1. 模反元素 RSA Euler's totient function

    https://baike.baidu.com/item/模反元素/20417595 如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1.这时,b就 ...

  2. 在VS13上编译通过的代码放在12上编译-错误:l __dtoui3 referenced in function _event_debug_map_HT_GROW

    在VS13上编译通过的代码放在12上编译 遇到错误:l __dtoui3 referenced in function _event_debug_map_HT_GROW 1>------ 已启动 ...

  3. 死磕Lambda表达式(六):Consumer、Predicate、Function复合

    你的无畏来源于无知.--<三体> 在上一篇文章(传送门)中介绍了Comparator复合,这次我们来介绍一下其他的复合Lambda表达式. Consumer复合 Consumer接口中,有 ...

  4. Project Euler 77:Prime summations

    原题: Prime summations It is possible to write ten as the sum of primes in exactly five different ways ...

  5. Javacript中(function(){})() 与 (function(){}()) 区别 {转}

    这个问题可以从不同的角度来看,但从结果上来说 :他们是一样的.首先,如果从AST(抽象语法树)的角度来看,两者的AST是一模一样的,最终结果都是一次函数调用.因此,就解析器产生的结果论而言,两者是没有 ...

  6. function,new function,Function,new Function 之间的区别

    测试一: var fud01 = function()  { var temp = 100; this.temp = 200; return temp + this.temp; } alert(typ ...

  7. 浅析jQuery(function(){})与(function(){})(jQuery)之间的区别

    本篇文章主要是对jQuery(function(){})与(function(){})(jQuery)之间的区别进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助 Jquery是优秀的Javas ...

  8. jQuery中$(function(){})与(function($){})(jQuery)、$(document).ready(function(){})等的区别详细讲解

    1.(function($) {…})(jQuery); 1).原理: 这实际上是匿名函数,如下: function(arg){…} 这就定义了一个匿名函数,参数为arg 而调用函数时,是在函数后面写 ...

  9. (function($){}) 和$(function(){}) 和$(function($){}) 区别

    请问下(function($){}) 和$(function(){}) 和$(function($){}) 有什么区别 谢谢 一.先看 jQuery(function(){ }); 全写为 jQuer ...

随机推荐

  1. nginx 配置实例-反向代理

    反向代理实例一 虚拟机IP:192.168.116.129实现效果:使用 nginx 反向代理,访问 www.123.com 直接跳转到 虚拟机的192.168.116.129:8080  实验代码  ...

  2. Python备份脚本(Win10+Python2.7+PyCharm)

    说一下程序来源,是从<Python简明教程>上面看到的程序,试了一下之后,居!然!不!行!!! Google了老半天,也看了好多个博客,也未能解决. 除了一些基本语法问题.字符串中队'\' ...

  3. 【朝花夕拾】Android性能篇之(八)来自官网的自白

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10823372.html],谢谢! Android性能优化无疑是Android中的一个重点,也是 ...

  4. 动态SQL与变量绑定

    有时候动态sql需要进行变量的赋值,这个时候就需要调用系统的存储过程sp_executesql了.使用中还是有些注意事项,代码如下: --字符型字段需声明为NVARCHAR类型 ),) --动态SQL ...

  5. Dynamics CRM命令栏定制基础知识及手动编辑customization.xml实例

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复166或者20151028可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! 前面的博文:Dynamics C ...

  6. Android Gradle 学习笔记(二):Gradle Wrapper

    Wrapper,就是对Gradle的一层包装,便于在团队开发过程中统一Gradle构建的版本.这样大家就可以使用统一的Gradle版本进行构建,避免因为Gradle的版本不统一带来的不必要的问题. 这 ...

  7. Spring的常用注解

    Spring框架主要包括IoC和AOP,这两大功能都可以使用注解进行配置. 开发环境:IntelliJ IDEA 2019.2.2Spring Boot版本:2.1.8新建一个名称为demo的Spri ...

  8. 【转】java的string中,关于split空串总会返回单个元素的数组

    原地址:http://blog.sina.com.cn/s/blog_6f3da9650102x03c.html public class Split { public static void mai ...

  9. iTerm2 使用代理

    0x00 事件 因为 brew 安装极慢,所以需要 iTerm2 设置代理解决速度问题. 0x01 解决 代理软件开启本地 Http 端口: iTerm 设置代理: $ vim ~/.zshrc # ...

  10. idea找不到terminal

    起因是这样的,我要用命令行,懒,不想开cmd但是该死的我的idea找不见terminal,好奇怪哦,于是我查了一下,原来设置它蒙蔽了我的眼. 下面给出流程: 一般像我这样比较好学的好孩子不懂就比较喜欢 ...