牛客练习赛25 因数个数和(贡献法)

本文介绍了一种高效算法,用于计算1到任意整数x的所有整数的因数个数之和。通过巧妙地将问题转化为寻找相同因数个数的区间,避免了直接枚举所带来的巨大计算成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:q次询问,每次给一个x,问1到x的因数个数的和。

思路:考虑1到x的数的因子为1有x/1,因子为2有x/2,……,所以要求的就是\sum_{i=1}^{x}x/i,因为数据是1e9,这样写绝对超时。我们换一个角度,相等的因子个数应该在某个特定的区间出现,比如x=12,有1 ,1 2,1 3,1 2 4,15,1 2 3 6,17,1 2 4 8,1 3 9,1 2 5 10,1 11,1 2 3 4 6 12。对应的因子个数为:1,2,2,3,2,4,2,4,3,4,2,6。ans=12+6+4+3+2+2+1+1+1+1+1+1。

从ans式子可以看出,12/5和12/6都是2,12/7和12/8和……12/12都是1,对应的区间为【5,6】,【7,12】。这些区间的l和r是可以算出来的,令i从1开始,r=x/(x/i),括号的x/i可以取整,也就可以找到r的最大值(因为x/i取整肯定小于x/i),再令i=r+1,继续操作就行了。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=200005;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
int main()
{
    int q;
    cin>>q;
    for(int i=0; i<q; i++)
    {
        int x;
        cin>>x;
        ll sum=0;
        for(int i=1,r; i<=x; i=r+1)
        {
            r=x/(x/i);
            sum+=1ll*(x/i)*(r-i+1);
        }
        printf("%lld\n",sum);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值