We all know that any integer number n is divisible by 1 and n. That is why these two numbers are not the actual divisors of any numbers. 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.
The function CSOD(n) (cumulative SOD) of an integer n, is defined as below:
Given the value of n, your job is to find the value of CSOD(n).
Input
Input starts with an integer T (≤ 1000), denoting the number of test cases.
Each case contains an integer n (0 ≤ n ≤ 2 * 109).
Output
For each case, print the case number and the result. You may assume that each output will fit into a 64 bit signed integer.
Sample Input
3
2
100
200000000
Sample Output
Case 1: 0
Case 2: 3150
Case 3: 12898681201837053
题目是求1-n所有数字因子的和(因子不包括1和n这两个)。 这里我先求包括因子1和n的总和,这样结果肯定大了,但是最后减一下就好了(多余的部分也很好计算)。那怎么求我定义的这个呢?(假设我定义的最后结果为s(n))
S(n) = sigma( i : 1 - n ) ( floor( n / i ) * i )
然后再减去多计算的部分 就好了。
你可能无法理解这个公式 之前做过一个更简单的题目这里面的A题
懂了上面的公式之后。
我们发现时间复杂度还是不够啊,必须要化简为o(sqrt(n))的好像才可以过。
这就体现到了 数学题目中,缩小时间复杂度常用的手段: 从结果考虑,从可能产生的结果来考虑 什么样的情况会导致这个结果 。
(描述的不是很清楚,大家可以自己找规律来理解)
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = (int)1e8+2;
const int M = 1E6+11;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
LL n;
LL get(LL x){ //对于每个可能的结果,1-n的一定会有一段区间的数字 会导致这样的结果
LL a=n/x;
LL b=n/(x+1)+1;
return (a+b)*(a-b+1)/2*x;
}
int main(){
int cas=1;
int T;scanf("%d",&T);
while(T--){
scanf("%lld",&n);
LL ans=0;
for(LL i=1;i*i<=n;i++){
LL a=i;
LL b=n/a; // a 和 b 就是 公式中 floor(n/i) 所有的可能结果之一 (之所以这样遍历得到,是因为我找了好几组数据 试了一下找到了规律)
ans+=get(a);
if(b!=a) ans+=get(b);
}
ans-=n+(2+n)*(n-2+1)/2;// 减去多计算的部分
if(n==0) ans=0;
printf("Case %d: %lld\n",cas++,ans);
}
return 0;
}