1. 程式人生 > >1098 】A New Function 【數論+思維】 1-n 每個數的因子的和

1098 】A New Function 【數論+思維】 1-n 每個數的因子的和

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;
}