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=10000000+10;
int ps[N],cnt;
bool v[N];
int n,m;
void sieve(){
    for(int i=2;i<=n;i++){
        if(v[i]==0){
            ps[++cnt]=i;
        }
        for(int j=1;j<=cnt;j++){
            if(i*ps[j]>n) break;
            v[i*ps[j]]=1;
            if(i%ps[j]==0) break;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    sieve();
    v[1]=1;
    int t;
    for(int i=1;i<=m;i++){
        scanf("%d",&t);
        if(v[t]) printf("No\n");
        else puts("Yes");
    }
    return 0;
}

看不懂...................

解释:
对于一个质数,之前没有被标记。肯定只会有一次查到。把它记录到素数集合里去。

然后,不论这个数是否为质数,都将已有的质数从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的形式找到一次。而内层循环每一次都对应一个将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(){
    for(int i=2;i<=n;i++){
        if(v[i]==0){
            fai[i]=i-1;
            pri[++cnt]=i;
        }
        for(int j=1;j<=cnt;j++){
            if(i*pri[j]>n) break;
            v[i*pri[j]]=1;
            if(i%pri[j]==0) {
                fai[i*pri[j]]=fai[i]*pri[j];break;
            }
            else{
                fai[i*pri[j]]=fai[i]*(pri[j]-1);
            }
        }
    }
}

并不想从积性函数性质入手解释。

显然的,当处理到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 仪仗队

原文地址:https://www.cnblogs.com/Miracevin/p/9251873.html

时间: 2024-08-29 22:37:34

SIEVE 线性筛的相关文章

BZOJ 2693: jzptab [莫比乌斯反演 线性筛]

2693: jzptab Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1194  Solved: 455[Submit][Status][Discuss] Description Input 一个正整数T表示数据组数 接下来T行 每行两个正整数 表示N.M Output T行 每行一个整数 表示第i组数据的结果 Sample Input 1 4 5 Sample Output 122 HINT T <= 10000 N, M<=1000000

Codeforces 893E Counting Arrays:dp + 线性筛 + 分解质因数 + 组合数结论

题目链接:http://codeforces.com/problemset/problem/893/E 题意: 共q组数据(q <= 10^5),每组数据给定x,y(x,y <= 10^6). 问你有多少种长度为y,乘积为x的整数数列.(可以有负数) 题解: 首先考虑数列只有正整数的情况. 将x分解质因数:x = ∑ a[i]*p[i] 由于x较大,所以要先用线性筛求出素数,再枚举素数分解质因数. 那么一个乘积为x的数列可以看做,将x的所有∑ p[i]个质因子,分配到了y个位置上. 设f(i)

线性筛与积性函数

线性筛 最初,线性筛只是用来筛质数罢了... void sieve(int n) { static int v[N], p[N], pr; // v[i] 表示 i 的最小质因子 // p[N] 和 pr 用来存质数表 for (int i = 2; i <= n; ++i) { if (v[i] == 0) v[i] = i, p[++pr] = i; // 没被筛,是质数 for (int j = 1; j <= pr && i*p[j] <= n; ++j) { v

模板 - 数论 - 线性筛

各种线性筛的合集: https://www.cnblogs.com/zhoushuyu/p/8275530.html 常见积性函数: μ(n):莫比乌斯函数φ(n):欧拉函数d(n):一个数nn的约数个数σ(n):一个数nn的约数和f(x)=x^k(k∈N):这个玩意儿也是积性函数 线性筛素数 int pri[N],tot,zhi[N];//zhi[i]为1的表示不是质数 void sieve() { zhi[1]=1; for (int i=2;i<=n;i++) { if (!zhi[i])

模板 - 数学 - 数论 - 线性筛

线性筛质数,可以通过输出ptop之后调整p数组的大小.pm[i]表示i的最小质因子,pk[i]表示含有i的最小质因子的幂.其他的积性函数主要依靠pk的值来求解,比如现在枚举的是t,求出了他的最小质因子的幂pk[t],那么t/pk[t]与pk[t]显然是互质的.当t==pk[t]时,则t是p[j]的幂次,一般积性函数在质数的幂次都要特殊求解,不过欧拉函数和莫比乌斯函数可以直接从低一级的幂次转移过来.当t!=pk[t]时,直接分解成两个互质的数的乘积.要注意这个算法的空间消耗巨大. 1ex内的质数数

bzoj 3309 DZY Loves Math - 莫比乌斯反演 - 线性筛

对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b). Input 第一行一个数T,表示询问数. 接下来T行,每行两个数a,b,表示一个询问. Output 对于每一个询问,输出一行一个非负整数作为回答. Sample Input 4 7558588 9653114 6514903 445

jzp线性筛及其简单应用

前言: 很久以前看过了线性筛,没怎么注意原理,但是后来发现线性筛还有很有用的.. 比如上次做的一道题就需要找出每个数的最小质因子,先筛再找就太慢了..一看线性筛发现就可以直接在筛的过程中处理出来了! 今天又学习了屌炸天的jzp线性筛,可以在o(n)的时间内求出欧拉函数, 莫比乌斯函数等积性函数 原理: 首先jzp线性筛并不是一种新的线性筛..其实就是jzp大牛对线性筛的一些开发应用 先回忆一下积性函数的定义 若a,b互质 则f(ab)=f(a)*f(b)的函数f 定义为积性函数,不要求a,b互质

* SPOJ PGCD Primes in GCD Table (需要自己推线性筛函数,好题)

题目大意: 给定n,m,求有多少组(a,b) 0<a<=n , 0<b<=m , 使得gcd(a,b)= p , p是一个素数 这里本来利用枚举一个个素数,然后利用莫比乌斯反演可以很方便得到答案,但是数据量过大,完全水不过去 题目分析过程(从别人地方抄来的) ans = sigma(p, sigma(d, μ(d) * (n/pd) * (m/pd))) Let s = pd, then ans = sigma(s, sigma(p, μ(s/p) * (n/s) * (m/s))

[原博客] 关于线性筛

埃氏筛法:从2开始,找到第一个没有被筛的数,把它标记为素数,然后把它的2倍.3倍……筛掉.复杂度O(nlogn). 改进的埃氏筛法:从2开始,找到第一个没有被筛的数x,把它标记为素数,然后把它的x倍.x+1倍……筛掉.复杂度O(nloglogn). 线性筛:保证每个数都被它的最小素因子筛掉.复杂度O(n). C++写起来大概是这样的: int mindiv[10000005],tot,prime[10000050]; int main(){ for(int i=2;i<=10000000;i++