线性筛约数个数和、约数和

 

筛约数个数和

理论基础:ide

一、对n质因数分解,n=p1^k1 * p2^k2 * p3^k3 ……函数

则n的约数个数为(k1+1)*(k2+1)*(k3+1)……spa

二、线性筛素数时,用i和素数pj来筛掉 i*pj,code

其中pj必定是i*pj的最小素因子blog

若是i是pj的倍数,pj也是i的最小素因子io

 

设t[i] 表示i的约数个数,e[i] 表示i的最小素因子的个数event

A、若是i是质数,t[i]=2,e[i]=1class

B、若是i不是质数,枚举已有的质数pj基础

i*pj的最小素因子是pjcli

一、若是i是pj的倍数那么e[i]即为i中包含的pj的个数,因此i*pj中包含的pj的个数为e[i]+1

       因此e[i*pj]=e[i]+1,t[i*pj]=t[i]/(e[i]+1)*(e[i]+2)

二、若是i不是pj的倍数,e[i*pj]=1,t[i*pj]=t[i]*t[pj](积性函数的性质)=t[i]*2(素数的约数个数=2)

 

#include<cstdio>

using namespace std;

#define N 1000001

bool vis[N];
int prime[N];

int t[N],e[N];

int main()
{
    int n;
    scanf("%d",&n);
    int cnt=0;
    t[1]=1;
    for(int i=2;i<=n;++i)
    {
        if(!vis[i])
        {
            prime[++cnt]=i;
            t[i]=2;
            e[i]=1;
        }
        for(int j=1;j<=cnt;++j)
        {
            if(i*prime[j]>n) break;
            vis[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                t[i*prime[j]]=t[i]/(e[i]+1)*(e[i]+2);
                e[i*prime[j]]=e[i]+1;
                break;
            }
            else 
            {
                t[i*prime[j]]=t[i]*2;
                e[i*prime[j]]=1;
            }
        }
    }
    long long ans=0;
    for(int i=1;i<=n;++i) ans+=t[i];
    printf("%lld",ans);
}
View Code

 

 

筛约数和

t[i] 表示i的约数和

e[i] 表示i的约数中,不能被i的最小素因子整除的约数和

A、i是质数,t[i]=i+1,e[i]=1

B、i不是质数

i*pj的最小素因子是pj

一、若是i不是pj的倍数,那么i的全部约数中,必然没有pj的倍数

能够用反证法证实这个:设x是i的约数,且x是pj的倍数,

那么 x=pj*b,i=x*a=pj*b*a

即i是pj的b*a倍,与i不是pj的倍数相矛盾

令S表示i的约数集,S’表示i的约数翻pj倍后的数的集合

则S∩S’=∅,则S和S’中无重复元素

因此t[i*pj]=S+S'=t[i]+t[i]*pj=t[i]*(pj+1)

S’中的全部元素都能整除pj,因此e[i*pj]=t[i]

二、若是i是pj的倍数,那么S和S’必有交集T

T=S中pj的倍数

因此i*pj的约数和要去除交集T

那么t[i*pj]=S+S'-T=S'+S-T=t[i]*pj+e[i]

由于pj既是i的最小素因子,有事i*pj的最小素因子

因此e[i*pj]=e[i]

 

 

#include<cstdio>

typedef long long LL;

#define N 100001

int prime[N];
bool vis[N];

LL t[N],e[N];

int main()
{
    int n;
    scanf("%d",&n);
    int cnt=0;
    for(int i=2;i<=n;++i)
    {
        if(!vis[i])
        {
            prime[++cnt]=i;
            t[i]=i+1;
            e[i]=1;
        }
        for(int j=1;j<=cnt;++j)
        {
            if(prime[j]*i>n) break;
            vis[prime[j]*i]=true;
            if(i%prime[j]==0)
            {
                t[i*prime[j]]=t[i]*prime[j]+e[i];
                e[i*prime[j]]=e[i];
                break;
            } 
            t[i*prime[j]]=t[i]*(prime[j]+1);
            e[i*prime[j]]=t[i];
        }
    }
    LL ans=0;
    for(int i=1;i<=n;++i) ans+=t[i];
    printf("%lld",ans);
}
View Code
相关文章
相关标签/搜索