SIEVE 线性筛
今天来玩玩筛
英文:Sieve
有什么筛?
这里介绍:素数筛,欧拉筛,约数个数筛,约数和筛
为什么要用筛?
顾名思义,筛就是要漏掉没用的,留下有用的。最终筛出来1~n的数的一些信息。
为什么要用线性筛?
考虑最基础的线性筛素数,是O(n)的。
而一般的做法是:
1.对于每个m暴力枚举1~sqrt(m)看能否被整除。O(nsqrt(n))
2.对于每个找到的素数,用它去将所有它的倍数的数都干掉。O(nlogn)
但是,即使是第二种,也有一个log
这是因为一个合数会被它的所有质因子筛一次。要重复质因子个数次,除第一次之外都没用。
所以用线性筛
线性筛原理:
一个算法,使得每个合数只被它的最小质因子筛一次。
怎么保证呢?
素数线性筛:
先看代码:
#include<bits/stdc++.h>
using namespace std;
const int N=+;
int ps[N],cnt;
bool v[N];
int n,m;
void sieve(){
for(int i=;i<=n;i++){
if(v[i]==){
ps[++cnt]=i;
}
for(int j=;j<=cnt;j++){
if(i*ps[j]>n) break;
v[i*ps[j]]=;
if(i%ps[j]==) break;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
sieve();
v[]=;
int t;
for(int i=;i<=m;i++){
scanf("%d",&t);
if(v[t]) printf("No\n");
else puts("Yes");
}
return ;
}
看不懂...................
解释:
对于一个质数,之前没有被标记。肯定只会有一次查到。把它记录到素数集合里去。
然后,不论这个数是否为质数,都将已有的质数从1~cnt循环一遍,把所有的i*ps[j]标记。
当i*ps>n break,可以理解。
当i%ps==0 break.???
这个时候,ps和i不互质了,而ps第一次整除i,所以ps就是i的最小质因数。叫他ps0
而之后,ps更大,ps*i的最小质因数就不是ps了。因为i里有ps0,这个合数就等着以后i更大了,通过ps0筛掉。
ps再大,后面的ps*i的最小质因数都不是ps,所以之前直接break掉就好。
由于每个合数只会被i*ps的形式找到一次(那一次的ps就是这个合数的最小质因子)。而内层循环每一次都对应一个将v[ps*i]=1的操作。
所以内层循环均摊O(1),总共O(n)
完毕。
欧拉线性筛:
代码:fai(i) 1~i中和i互质的数的个数。
可以容斥推出公式:假设:i=p1^q1*p2^q2*....pn^qn
那么,fai(i)=p1^(q1-1)*(p1-1) * p2^(q2-1)*(p2-1) * ......pn^(qn-1) * (pn-1)
证明不是本篇想讲的。
void sieve(){
fai[]=;
for(int i=;i<=n;i++){
if(v[i]==){
fai[i]=i-;
pri[++cnt]=i;
}
for(int j=;j<=cnt;j++){
if(i*pri[j]>n) break;
v[i*pri[j]]=;
if(i%pri[j]==) {
fai[i*pri[j]]=fai[i]*pri[j];break;
}
else{
fai[i*pri[j]]=fai[i]*(pri[j]-);
}
}
}
}
并不想从积性函数性质入手解释。
显然的,当处理到fai[i]的时候,i的值应该就知道了。i是质数就现成赋值。
考虑公式。
当i%ps==0 时,i的质因子中有ps,那么i*ps的质因子ps的次数就大于一,那么,就是fai[i]*ps了
否则,i*ps 的 ps的次数就是1,那么,ps^(1-1)*(ps-1)=(ps-1) 所以是fai[i]*(ps-1)
之后的各种操作基于线性筛的要求和特质。(即每个数只被它的最小质因子筛一次)
例题:SDOI2008 仪仗队
约数个数线性筛:
推荐:线性筛约数个数和、约数和
设x=p1^q1*p2^q2*....pn^qn
要知道公式:个数=(q1+1)*(q2+1)*...*(qn+1) 乘法原理就可以知道。
设t[i]表示i的约数个数
设e[i]表示i的最小素因子个数
①i是质数:t[i]=2,e[i]=1;
②i%pj!=0 这个时候,pj里面没有i,根据积性函数,或者乘法原理,t[i*pj]=t[i]*t[pj]=2t[i];
而 e[i*pj]=1
③i%pj==0 这个时候,pj里面至少有一个i,i也是pj的最小质因子。
t[i*pj]=t[i]/(e[i]+1)*(e[i]+2) 考虑公式,i*pj只在pj的位置上加了1,所以先除掉,再乘上去。
e[i*pj]=e[i]+1 最小素因子个数多了一个。
约数和的线性筛:
(很详细的解释)
设x=p1^q1*p2^q2*....pn^qn
首先还是要知道公式:和=(1+p1^1+...+p1^q1)*(1+p2^1+...+p2^q2)*...*(1+pn^1+...+pn^qn)
证明很简单,加数的个数显然就是约数个数,每次选择就是这个约数个数的质因数分解形式,数值就是这个约数的数值。
设t[i]表示i的约数和
设e[i]表示i的最小素因子对约数和的答案的贡献,即:(1+p1^1+...+p1^q1)(假设p1是最小质因子)
①当i是质数的时候,t[i]=i+1;e[i]=i+1;
②i%pj!=0 根据公式、积性函数性质 : t[i*pj]=t[i]*t[pj]
e[i*pj]=1+pj;
③i%pj==0
t[i*pj]=t[i]/e[i]*(pj*e[i]+1)
证明:考虑公式,i里面有pj的贡献,乘了一个pj,相当于多了一个pj^(qj+1)所以除掉后,乘上错位,再加一
而 e[i*pj]=e[i]*pj+1
就这样。代码参考上面的写就是了,没什么难度。
莫比乌斯函数筛:
知道定义就好说:
μ(i)={
0 i有平方因子
1 i的质因子个数为偶数
-1 i的质因子个数为奇数
}
根据定义直接筛就好了。
void sieve(){
u[]=;
for(int i=;i<=N;i++){
if(!vis[i]){
u[i]=-;
pr[++cnt]=i;
}
for(int j=;j<=cnt;j++){
if(pr[j]*i>N) break;
vis[pr[j]*i]=;
if(i%pr[j]==) {
u[pr[j]*i]=;break;
}
else u[pr[j]*i]=-u[i];
}
}
}
例题:bzoj2440 完全平方数
SIEVE 线性筛的更多相关文章
- BZOJ 2693: jzptab [莫比乌斯反演 线性筛]
2693: jzptab Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1194 Solved: 455[Submit][Status][Discu ...
- BZOJ 2818: Gcd [欧拉函数 质数 线性筛]【学习笔记】
2818: Gcd Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4436 Solved: 1957[Submit][Status][Discuss ...
- BZOJ 3309: DZY Loves Math [莫比乌斯反演 线性筛]
题意:\(f(n)\)为n的质因子分解中的最大幂指数,求\(\sum_{i=1}^n \sum_{j=1}^m f(gcd(i,j))\) 套路推♂倒 \[ \sum_{D=1}^n \sum_{d| ...
- Codeforces 893E Counting Arrays:dp + 线性筛 + 分解质因数 + 组合数结论
题目链接:http://codeforces.com/problemset/problem/893/E 题意: 共q组数据(q <= 10^5),每组数据给定x,y(x,y <= 10^6 ...
- 洛谷 - P1891 - 疯狂LCM - 线性筛
另一道数据范围不一样的题:https://www.cnblogs.com/Yinku/p/10987912.html $F(n)=\sum\limits_{i=1}^{n} lcm(i,n) $ $\ ...
- Codeforces 1047C (线性筛+因数分解)
题面 传送门 分析 1.暴力做法 首先先把每个数除以gcd(a1,a2-,an)gcd(a_1,a_2 \dots,a_n )gcd(a1,a2-,an) 可以O(namax)O(n\sqrt ...
- 莫比乌斯反演/线性筛/积性函数/杜教筛/min25筛 学习笔记
最近重新系统地学了下这几个知识点,以前没发现他们的联系,这次总结一下. 莫比乌斯反演入门:https://blog.csdn.net/litble/article/details/72804050 线 ...
- bzoj2693--莫比乌斯反演+积性函数线性筛
推导: 设d=gcd(i,j) 利用莫比乌斯函数的性质 令sum(x,y)=(x*(x+1)/2)*(y*(y+1)/2) 令T=d*t 设f(T)= T可以分块.又由于μ是积性函数,积性函数的约束和 ...
- 【BZOJ-4514】数字配对 最大费用最大流 + 质因数分解 + 二分图 + 贪心 + 线性筛
4514: [Sdoi2016]数字配对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 726 Solved: 309[Submit][Status ...
随机推荐
- 如何使用chrome浏览器进行js调试找出元素绑定的点击事件
大家有没有遇到这样的一个问题,我们在分析一些大型电子商务平台的Web前端脚本时,想找到一个元素绑定的点击事件,并不是那么容易,因为有些前端脚本封装的比较隐蔽,甚至有些加密脚本,用传统的查找元素ID.或 ...
- Centos7 中文乱码
1. 安装中文库 yum groupinstall "fonts" 2. 检查是否有中文语言包 locale -a 3. 查看当前系统语言环境 locale 解析如下 LANG:当 ...
- Nginx的location配置规则梳理
Nginx几乎是当下绝大多数公司在用的web应用服务,熟悉Nginx的配置,对于我们日常的运维工作是至关重要的,下面就Nginx的location配置进行梳理: 1)location匹配的是nginx ...
- 广商博客冲刺第四五天new
第三天沖刺傳送門 第六七天沖刺傳送門 以上的前台设计架构已经完成了,现在来完成前台的安卓设计. 首先我们配置了Android SDK Manager 使得程序能在安卓环境下运行. 这就完成了前台安卓的 ...
- node基础 npm、module、exports、require
module 模块.包:可以认为是一个代码包,package,提供特定的功能(暴露给外界接口,让外界调用) exports 输出.导出:导出模块中的各种类型的变量,以及各种方法,导出之后,才可以被外界 ...
- linux系统centOS7下搭建redis集群中ruby版本过低问题的解决方法
问题描述: 在Centos7中,通过yum安装ruby的版本是2.0.0,但是如果有些应用需要高版本的ruby环境,比如2.2,2.3,2.4... 那就有点麻烦了,譬如:我准备使用redis官方给的 ...
- 【转帖】2018年Windows漏洞年度盘点
2018年Windows漏洞年度盘点丨老漏洞经久不衰,新0day层出不穷 腾讯电脑管家2019-02-12共17875人围观 ,发现 1 个不明物体网络安全资讯 https://www.freebuf ...
- 原生NodeJs制作一个简易聊天室
准备工作 安装NodeJs环境 安装编译器Sublime 如果网速不理想,可以百度一下如何加快npm的速度~ 使用node搭建一个简单的网站后台 做完准备工作之后,新建文件夹chatroom,在cha ...
- Python装饰器的深入理解
装饰器 #装饰器:本质上是函数,(装饰其他函数)就是为其他函数添加附加功能 #原则: 1.不能修改被装饰的函数的源代码 # 2.不能修改被装饰的函数的调用方式 #实现装饰器知识储备 #1.函数即变量 ...
- MySQL_基础知识
-----基础知识 1.什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库 2.什么是关系型数据库.主键,外键,索引分别是什么? 关系型数据 ...