LOJ 1089

题意 : 

The function SOD(n) (sum of divisors) is defined as the summation of all the actual divisors of an integer number n. For example, SOD(24) = 2+3+4+6+8+12 = 35.

给出一个n,让求csod(n), n的范围在2*10^9;

思路: 这道题主要的思想是枚举除数, 很显然在n的范围内除数可以出现的值在2~~n。

每个除数i,出现的次数为(n/i-1), 其值为(n/i-1)*i; 我们可以算 sum(n/i*i),最后再把多余的项给补出来。

如果一个一个枚举的话肯定会tle的。 然后就是如何降低复杂度,其实对于每道题,看到数据之后应该想着正解算法的复杂度大概是多少,复杂度是这样的算法有哪些?然后就是如何才能降低这个复杂度呢? 

其实给出了这个n的范围我们应该往√n 的复杂度上想。首先√n以前的数可以枚举,√n后的数n/i的值是在一些区间中的。并且这些区间中的值是连续的。 我们可以利用这个性质,并且只有√n 个区间。 n/i == k 的区间是[n/(k+1)+1, n/k];

 这道题RE一次。 主要是0的时候出现了一次。 数论题可能会有一些有特例(一般是小数据)。

AC代码:

View Code
 1 #include <cstdio>
 2 #include <string>
 3 #include <queue>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <iostream>
 7 using namespace std;
 8 typedef unsigned long long ULL;
 9 
10 ULL n;
11 
12 int main()
13  {
14      int t;
15      n = 2;
16      scanf("%d", &t);
17      ULL ans, ss, l, r, k;
18      for(int i=1; i<=t; i++)
19       {
20           scanf("%llu", &n);
21           printf("Case %d: ", i);
22           if(n <= 3)
23            {
24                puts("0");
25                continue;
26            }
27           ans = 0;
28           ss = (ULL)sqrt(n*1.0);
29           for(int i=2; i<=ss; i++)
30            {
31                ans += n/i*i;
32            }
33           l = ss+1;
34           k = n/l;
35           r = n/k;
36           ans += k*(r+l)*(r-l+1)/2;
37           for(ULL j=k-1; j>=1; --j)
38            {
39                l = n/(j+1) +1;
40                r = n/j;
41                ans += j*(r+l)*(r-l+1)/2;
42            }
43            
44           ans -= (2+n)*(n-2+1)/2;
45           printf("%llu\n", ans);
46       }
47      return 0;
48  }

 

你可能感兴趣的:(LOJ 1089)