小G的约数
题目链接:nowcoder 218398
到牛客看:
题目大意
定义 F(n) 是 n 的约数的和,然后 G(n) 则是 1~F(n) 的和。
然后问你 G(G(n)) 是多少。
思路
首先,我们会想到,暴力算是不行的。
然后我们考虑优化算 G ( n ) G(n) G(n) 怎么弄。
我们先看约数有什么特别的地方,那有约数,又有前缀和,那如果对于一个数 x x x,它会是哪些数的因子呢?
x , 2 x , 3 x , 4 x , . . . , k x x,2x,3x,4x,...,kx x,2x,3x,4x,...,kx
( k = ⌊ n x ⌋ k=\left\lfloor\dfrac{n}{x}\right\rfloor k=⌊xn⌋,也就是会有多少个数含有这个因子)
但是你会想到,就算你每次只枚举因子,你还是会超时。
( G ( 50000 ) = 2056198403 G(50000)=2056198403 G(50000)=2056198403)
然后你会从整除向下取整想到一个叫做整除分块的东西。
然后你会想到在一个块中,它的 k k k 都是一样的,然后因子的大小是每次加一。
那这就是一个等差序列,可以 O ( 1 ) O(1) O(1) 搞。
那块的个数是 n \sqrt{n} n,那时间就过去了。
代码
#include<cstdio>
#define ll long long
using namespace std;
ll n;
ll g(ll now) {
//求 G(n)
ll re = 0;
for (ll i = 1; i <= now; i++) {
ll r = now / (now / i);//整除分块确定右边界
re += (now / i) * (i + r) * (r - i + 1ll) / 2;
i = r;
}
return re;
}
int main() {
scanf("%lld", &n);
printf("%lld", g(g(n)));
return 0;
}