题意:定义SOD(n)=n除去1和自身的所有因数的和,CSOD(n)为ΣSOD(i),1<=i<=n。T (≤ 1000)组数据,求CSOD(n),(0 ≤ n ≤ 2 * 109)
对于不同的数m,m=a*b,a<=b;枚举a,判断不大于n的中有哪些可以写成m=a*b的,把a和b加到答案上。复杂度是O(√n)
如何维护答案呢?
举例子,作为a出现的3有多少次呢?是n/3 * 3吗?并不是。要注意到我们要求a<=b,那么从m=9开始,3才会作为a出现,而3,6中的因数3并不作为a对答案贡献。所以ans += (n / i - i + 1) * i;
a为一个数时,对应的b成等差数列,最大值是n / i,最小值是a+1,(注意m=a*a时,a只能算一次贡献, 所以这里不是a)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #define INF 0x3f3f3f3f 6 using namespace std; 7 typedef long long LL; 8 9 int T; 10 LL N; 11 12 int main() { 13 scanf("%d", &T); 14 for (int t = 1; t <= T; t++) { 15 LL ans = 0; 16 scanf("%lld", &N); 17 LL tmp = sqrt(N); 18 for (LL i = 2; i <= tmp; i++) { 19 ans += (N / i - i + 1) * i; 20 LL down = i + 1, up = N / i; 21 //if (down > up) continue; 因为down > up的情况只会出现于n可表示为n=x *x 的情况,此时down = up + 1。下方右式恰好为0 22 ans += (up + down) * (up - down + 1) / 2; 23 } 24 printf("Case %d: %lld ", t, ans); 25 } 26 return 0; 27 }