线性筛d&&sd(约数个数&&约数和)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wu_tongtong/article/details/79684277

d函数

d(n)表示n的约数个数和

百度一下,我们就可以得到一个计算d函数的暴力做法

n=p1a1p2a2...pkak
d(n)=(a1+1)(a2+1)...(ak+1)

显然d是一个积性函数,我们可以用线性筛求出

prime[i]表示第i个质数
num[i]表示i的最小质因子出现次数

首先我们可以观察一下线性筛素数:

void prepare() {
    for (int i=2;i<N;i++) {
        if (!no[i]) sshu[++tot]=i;
        for (int j=1;j<=tot&&sshu[j]*i<N;j++) {
            no[sshu[j]*i]=1;
            if (i%sshu[j]==0) {
                no[sshu[j]*i]=1;
                break;
            }
        }
    }
}

我们之所以可以保证上述算法是线性的
就是因为:if (i%sshu[j]==0) break;
也就是说,每个数只会被ta的最小质因子筛掉

① 当前数是质数

很显然,d[n]=2,num[n]=1

②i%prime[j]!=0

这种情况下,i没有prime[j]这个质因子
然而iprime[j]中包含了一个prime[j]
前面我们已经得到了d[i]
d[i]=(a1+1)(a2+1)...(ak+1)

然后我们在这之后补上一个prime[j]
d[iprime[j]]=(a1+1)(a2+1)...(ak+1)(1+1)
d[iprime[j]]=d[i]d[prime[j]]=d[i]2

而且由于当前的prime[j]必然是iprime[j]的最小素因子(因为从小到大枚举), 我们要记录下这个最小素因子的个数

num[iprime[j]]=1

③i%prime[j]=0

这种情况下,i中必然包含了至少一个prime[j]
而且prime[j]也必定是i的最小质因数

iprime[j]比起i则是多了一个最小质因子

d[i]=(a1+1)(a2+1)...(ak+1)
d[iprime[j]]=(a1+1+1)(a2+1)...(ak+1)

那么d[iprime[j]]=d[i]/(a1+1)(a1+2)
num[iprime[j]]=num[i]+1

void prepare() {
    d[1]=1; num[1]=1;
    for (int i=2;i<N;i++) {
        if (!no[i]) {
            sshu[++tot]=i;
            d[i]=2; num[i]=1;
        }
        for (int j=1;j<=tot&&sshu[j]*i<N;j++) {
            int v=sshu[j]*i;
            no[v]=1;
            if (i%sshu[j]==0) {
                num[v]=num[i]+1;
                d[v]=d[i]/num[v]*(num[v]+1);
                break;
            }
            d[v]=d[i]<<1; num[v]=1;
        }
    }
    //for (int i=1;i<=10;i++) printf("%d\n",d[i]);
}

sd函数

sd(n)表示n的所有约数之和

再次百度一下,我们就可以得到一种比较暴力的sd计算方法

n=p1a1p2a2...pkak
sd(n)=(1+p1+p12+p13+...+p1a1)(1+p2+p22+...+p2a2)...(1+p3+p32+...+p3a3)

又是一个积性函数,我们可以考虑用线性筛筛出sd函数

prime[i]表示第i个质数
sp[i]表示i(1+p1+p12+...+p1a1)

① 当前数是质数

显然sd[n]=n+1,sq[n]=n+1

②i%prime[j]!=0

这种情况,i中不包含prime[j]这个质因子
而且prime[j]一定是iprime[j]的最小质因子

sd[i]=(1+p1+p12+...+p1a1)(1+p2+p22+...+p2a2)...(1+p3+p32+...+p3a3)
sd[iprime[j]]=(1+p1+p12+...+p1a1)...(1+p3+p32+...+p3a3)(1+prime[j])

sd[iprime[j]]=sd[i]sd[prime[j]]
sp[iprime[j]]=sp[prime[j]]=prime[j]+1

③i%prime[j]=0

这种情况下,i中至少包含了一个prime[j]

那么:
sd[i]=(1+p1+p12+...+p1a1)(1+p2+p22+...+p2a2)...(1+p3+p32+...+p3a3)
sd[iprime[j]]=(1+p1+p12+...+p1a1+p1a1+1)...(1+p3+p32+...+p3a3)

我们观察一下两式唯一的不同:
(1+p1+p12+...+p1a1)
(1+p1+p12+...+p1a1+p1a1+1)

sd[iprime[j]]=sd[i]/(1+p1+p12+...+p1a1)(1+p1+p12+...+p1a1+p1a1+1)

那么
sd[iprime[j]]=sd[i]/sp[i](sp[i]prime[j]+1)
sp[iprime[j]]=sp[i]prime[j]+1

void prepare() {
    sd[1]=1; sp[1]=1;
    for (int i=2;i<N;i+=) {
        if (!no[i]) {
            sshu[++tot]=i;
            sd[i]=i+1;
            sp[i]=i+1;
        }
        for (int j=1;j<=tot&&sshu[j]*i<N;j++) {
            int v=sshu[j]*i;
            no[v]=1;
            if (i%sshu[j]==0) {
                sp[v]=sp[i]*sshu[j]+1;
                sd[v]=sd[i]/sp[i]*sp[v];
                break;
            }
            sd[v]=sd[i]*sd[sshu[j]];
            sp[v]=sshu[j]+1;
        }
    }
}
阅读更多
换一批

没有更多推荐了,返回首页