洛谷P2424 约数和 题解

时间:2021-08-21
本文章向大家介绍洛谷P2424 约数和 题解,主要包括洛谷P2424 约数和 题解使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目

约数和

题解

此题可以说完全就是一道数学题,不难看出这道题所求的是 \(\sum\limits_{i=x}^{y}{\sum\limits_{d|i}{d}}\) 的值。

很显然,用暴力枚举肯定会超时。所以我们采用枚举约数的方法,对于每个数 \(d\)\(1\)\(n\) 间满足是\(d\)的倍数的共有\(\lfloor \frac{n}{d} \rfloor\)个数。所以我们构造一个函数

\[f(n)=\sum\limits_{i=1}^{n}{\sum\limits_{d|i}}d \]

转换后所求的值为 \(f(y)-f(x-1)\)

接下来我们只需专注于求 \(f(n)\) 即可。如加粗部分所说,不难得出 \(f(n)\) 可以转换为

\[f(n)=\sum\limits_{d=1}^{n}{d \cdot \lfloor\frac{n}{d}\rfloor} \]

似乎到这里直接计算已经很不错了,复杂度只有 \(O(x+y)\) ,然而依然会TLE。

所以我们还要想办法优化,注意到一点,对于每一个 \(n\) ,都有若干的 \(d\) 满足 \(\lfloor\frac{n}{d}\rfloor\) 都相等。举个栗子,比如 \(8\) ,当 \(d\)\(1\)\(8\) 分别取值时, \(\lfloor\frac{n}{d}\rfloor\) 的值分别为

\[8,4,2,2,1,1,1,1 \]

我们发现这里面有不少重复的数,我们则需要把这里面每个重复的数的个数算出来。

我们将 \(d\)\(1\) 开始枚举,也就是 \(1\) 作为左界 \(l\) ,那么请问右界 \(r\) 为什么呢(即 \(\lfloor\frac{n}{r}\rfloor=\lfloor\frac{n}{l}\rfloor\)\(\lfloor\frac{n}{r+1}\rfloor<\lfloor\frac{n}{l}\rfloor\) )?

其实很简单, \(r=\frac{n}{\lfloor n/l \rfloor}\) ,大家可以想一下是不是。然后运用等差数列求和的方式,对于每一个 \(\lfloor\frac{n}{l}\rfloor\) 结果 \(res\) 都要加上

\[\lfloor\frac{n}{l}\rfloor*\sum\limits_{i=l}^{r}{i} =(n/l)*(r-l+1)*(l+r)/2 \]

下一步再将 \(l\) 置为 \(r+1\) ,如此循环,直到 \(l>n\) 为止。

由此,这道题就愉快地解决了。

贴一下代码

代码极短,但浓缩了数学的精华。

#include<iostream>
using namespace std;
long long s(int n)
{
	if (n == 0)
		return 0;
	long long l, r;
	long long res = 0;
	for (l = 1; l <= n;l = r+1)
	{
		r = n / (n / l);
		res += (n / l) * (r - l + 1) * (l + r)/2;
	}
	return res;
}

int main()
{
	int x, y;
	cin >> x >> y;
	cout << s(y) - s(x - 1);
	return 0;
}

原文地址:https://www.cnblogs.com/Mobius-strip/p/15170556.html