luogu P2424 约数和

嘟嘟嘟

求出[L, R]中每一个数的约数再相加必定会超时,所以换一种思路:枚举约数d。

对于一个约数d,能整除他的数可以写成k * d, (1 <= k <= ⌊n / d⌋),因此约数d对答案的贡献是⌊n / d⌋ * d,f(i)表示[1, i]的约数和,那么f(n) = ∑⌊n / i⌋ * i  (1 <= i <= n)。因此x到y的答案等于f(y) - f(x - 1).

然而这样还是会TLE,考虑优化:对于⌊n / i⌋,以12为例打出一个表:12,6,4,3,2,2,1,1,1,1,1,1。想办法把相同的数字一次都算出来,令[L, R]表示相同的数的区间,那么L自然是上一次的R + 1,而R = n / (n / L)。因为⌊n / i⌋表示约数 i 在n中的出现次数,n / L就是约数,那么R = n / (n / L)。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<stack>
 9 #include<queue>
10 #include<vector>
11 using namespace std;
12 #define enter puts("")
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const int maxp = 1e6 + 5;
21 inline ll read()
22 {
23   ll ans = 0;
24   char ch = getchar(), las = ' ';
25   while(!isdigit(ch)) las = ch, ch = getchar();
26   while(isdigit(ch)) ans = ans * 10 + ch - '0', ch = getchar();
27   if(las == '-') ans = -ans;
28   return ans;
29 }
30 inline void write(ll x)
31 {
32   if(x < 0) putchar('-'), x = -x;
33   if(x >= 10) write(x / 10);
34   putchar(x % 10 + '0');
35 }
36 
37 int L, R, ans = 0;
38 
39 ll sum(int n)
40 {
41   if(n <= 1) return n;
42   ll ans = 0;
43   for(ll L = 1, R; L <= n; L = R + 1)
44     {
45       R = n / (n / L);
46       ans += (n / L) * (L + R) * (R - L + 1) >> 1;
47     }
48   return ans;
49 }
50 
51 int main()
52 {
53   L = read(); R = read();
54   write(sum(R) - sum(L - 1)); enter;
55   return 0;
56 }
View Code
原文地址:https://www.cnblogs.com/mrclr/p/9758352.html