[BZOJ1968][Ahoi2005]COMMON 约数研究(线性筛)

=== ===

这里放传送门

=== ===

题解

这道题的意思是求 [1,n] 内每个数约数个数的和。如果设 d(x) 表示 x 的约数个数,那么设x=pk11pk22...pknn,则 d(x)=(k1+1)(k2+1)...(kn+1) 。这个可以用排列组合的原理来理解,因为每个质因数 pi 都能拿出 0..ki 个质因数来构造新的约数,共有 ki+1 种可能性。还可以证明 d(x) 是一个积性函数,于是它可以用线性筛来求。为了求这个函数,还要记录一下最小质因子的指数 e(x) 用于最小质因子不为1的情况下的递推。具体递推过程如下:
- 对于一个数 i ,当i为质数的时候, d(i)=2 e(i)=1
- 当 i 的最小质因子p的指数为1的时候,显然 i/p p 是互质的,于是可以利用积性函数的性质,d(i)=d(i/p)d(p)=d(i/p)2
- 当 i 的最小质因子指数不为1的时候,因为最小质因子的次数增加了1,所以只要把d(i/p)里面质因子 p 贡献的那一部分改一下就可以了,具体就是因为一开始p的指数为 e(i/p) ,为 d(i/p) 贡献的那一部分是 e(i/p)+1 ,那么乘上一个 p 以后有

e(i)=e(i/p)+1

d(i)=d(i)e(i)(e(i)+1)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int d[1000010],e[1000010],n,prm[1000010];
bool ext[1000010];
long long sum;
int main()
{
    scanf("%d",&n);
    d[1]=e[1]=1;sum=1;
    for (int i=2;i<=n;i++){
        if (ext[i]==false){
            d[i]=2;e[i]=1;//质数的约数个数为2,最小质因子指数为1
            prm[++prm[0]]=i;
        }
        for (int j=1;j<=prm[0];++j){
            if (i*prm[j]>n) break;
            ext[i*prm[j]]=true;//不要忘了筛去合数
            if (i%prm[j]==0){
                d[i*prm[j]]=d[i]/(e[i]+1)*(e[i]+2);//在式子里面更新最小质因子的指数
                e[i*prm[j]]=e[i]+1;
                break;
            }
            else{
                d[i*prm[j]]=d[i]*d[prm[j]];
                e[i*prm[j]]=1;
            }
        }
        sum+=d[i];//一边筛一边累加前缀和
    }
    printf("%lld\n",sum);
    return 0;
}

偏偏在最后出现的补充说明

这都不知道啥时候做的题了只是拿出来玩 Markdown 哈哈哈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值