P2424 约数和——快速求l~r所有数的约数和的和


题目链接

暴力题解:

首先我们看暴力求1~n所有数的约数和的的和做法
遍历1~n,看每一个i他的倍数有多少个n/i, ans+=(n/i)*i;
参考大佬博客

#include<cstdio>

int main()
{
    int n,ans = 0;
    scanf("%d",&n);

    for (int i=1; i<=n; ++i)
    {
        ans += (n/i)*i;
    }

    printf("%d",ans);

    return 0;
}

优化

我们列举一个数12,可以发现数字1~12的倍数的个数依次为
12,6,4,3,2,2,1,1,1,1,1,1
我们发现倍数的个数在一个连续的区间可能会相同,这个区间我们看作[l,r], 代表倍数个数都相同。
可以发现这一次的l=上一次的r+1
所以对于一个区间对答案的贡献为这个区间的和(l+r)*(r-l+1)/2 等差数列求和,乘上他们倍数的个数n/l
比如7~12,这个区间的数的倍数的个数都是1,那么贡献就是

  • 1*(7+12)(12-7+1)/2;

代码

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(0),cin.tie(0)
#define gcd(a,b) __gcd(a,b)
#define ft first
#define sd second
#define endl '\n'
#define PI acos(-1.0)
inline void print(__int128 x)
{
	if(x<0) {putchar('-'); x=-x;}
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
const int N = 5e4+9;
ll Sum(ll n) {
    if(n<=1) return n;
    ll ans=0;
    for(ll l=1,r; l<=n; l=r+1)
    {
    	//n/l代表数字[l,r]出现的次数 
    	r=n/(n/l);
    	ans+=(n/l)*(l+r)*(r-l+1)/2; 
	}
    return ans;
}
int main()
{
	IOS;
	int x,y;
	cin>>x>>y;
	cout<<Sum(y)-Sum(x-1)<<endl;
	return 0;
} 

posted @ 2022-08-28 08:43  翔村亲亲鸟  阅读(58)  评论(0编辑  收藏  举报