码迷,mamicode.com
首页 > 其他好文 > 详细

线性筛--如何线性求约数个数

时间:2019-09-15 11:00:05      阅读:298      评论:0      收藏:0      [点我收藏+]

标签:知识   end   如何   ||   lag   素数   register   space   flag   

线性筛

我已经掌握埃氏筛了 为什么还要学线性筛???

线性筛的时间复杂度是严格 \(O(N)\) 的, 而埃氏筛的复杂度是 $ O(N * log_{2}( log_{2}(N) ) $

看上去并没有快多少 实际也是, 但在处理一些大数据时,差距就凸显出来了

算法思路

概述:

和埃氏筛类似的

线性筛是通过枚举到的当前数字乘以某个比该数的最小质因子还小的质数来筛的

(上面这句话有点长, 需要反复理解 暂时不能理解,也没关系,等下代码中我会详细讲的)

这样就可以保证每次几乎不会出现重筛的情况,大大减少了循环次数

代码:
#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define in inline
#define get getchar()
int read()
{
    int t=0; char ch=get;
    while(ch<'0' || ch>'9') ch=get;
    while(ch<='9' && ch>='0') t=t*10+ch-'0',ch=get;
    return t;
}
const int _=1e7+6;
int prime[_], tot, n; //tot是素数个数,prime是从小到大存放的素数数组 
bool flag[_];//用来判断当前数已为素数,flag==1不是素数 
int main()
{
    n=read();
    for (re int i=2;i<=n;i++)  
    {
        if (!flag[i]) prime[++tot]=i; // 当前数没有被打上非素数标记 
        for (re int j=1;j<=tot&&prime[j]*i<=n;j++)
        {      //保证prime[j]在已确定的素数范围内 
            flag[prime[j]*i]=1; //打上非素数标记 
            if(i%prime[j]==0) break; //若当前prime[j]已是i的约数
            //剩下的不用重复处理,所以直接break 
        }
    }
    cout<<"TOT:  "<<tot<<endl;
    for (re int i=1;i<=tot;i++)
        cout<<prime[i]<<' ';
    return 0;
}

用线性筛在线性时间里求1~n的约数个数

思路

记录数字 i 的最小约数出现次数 minn[i]
然后通过我们以前的知识 小学奥数 知道d(i)==(每个质因数的指数+1)的积
然后利用线性筛的性质递推 minn[i] 与 d[i] 就好

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define get getchar()
#define in inline
#define re register
const int _=10000001;
int minn[_],n,tot,prime[_],d[_];
bool np[_];
int main()
{
    cin>>n;
    d[1]=1;
    for(re int i=2; i<=n; i++)
    {
        if(np[i]==0) prime[++tot]=i,d[i]=2,minn[i]=1;
        for(re int j=1;prime[j]*i<=n&&j<=tot;j++)
        {
            np[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                minn[i*prime[j]]=minn[i]+1;
                d[i*prime[j]]=d[i]/(minn[i]+1)*(minn[prime[j]*i]+1);
                break;
            }
            minn[i*prime[j]]=1;
            d[i*prime[j]]=d[i]*2;
        }
    }
    for( re int i=1;i<=n;i++)
        cout<<d[i]<<' '; 
}

线性筛--如何线性求约数个数

标签:知识   end   如何   ||   lag   素数   register   space   flag   

原文地址:https://www.cnblogs.com/yzhx/p/11521073.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!