牛客網-因數個數和

【題目描述】
q次詢問,每次給一個x,問1到x的因數個數的和。1<=q<=10 ,1<= x <=10^9
【輸入描述】
第一行一個正整數q, 接下來q行,每行一個正整數 x
【輸出描述】
共q行, 每行一個正整數表示答案

【示例】
【輸入】
4
1
2
3
10
【輸出】
1
3
5
27

【思路分析】

方法1:最簡單的就是把1~x各個數的因數個數都求出來再求和。

不過這樣做顯然會超時。

方法2:換一種思路考慮,從1~x 這x個數,每個數都會有1這個因數,每2個數會有一個因數2,每3個數會有一個因數3,.......

所以,1~x 共有 x/1 個因數1,x/2個因數2,x/3個因數3,……,x/n個因數n(1<=n<=x),所以最終個數和爲\sum_{i=1}^{x}{x/i}

再寫代碼就比較簡單了,這裏就不贅述了。但還能不能把計算時間再縮小下呢,或者說有沒有計算量更小的方法呢?

方法3:假設n爲x的因數,那麼x/n 也一定爲x的因數,假設sq爲x的算術平方根,那麼x的因數可以分爲兩部分,一部分都小於sq,一部分都大於(等於)sq。基於方法2,我們也就只需要計算\sum_{i=1}^{sq}{x/i}的數值,然後再乘以2。於是我們興致勃勃的去寫代碼了,但是發現程序跑出來的結果並不正確。比之前多了許多。略作研究,我們發現,若x = 1,4,9,16等等,n=1,2,3,4等,n是x的因數,x/n的值正好也是n,我們盲目的乘以2,多計算了sq個。於是我們把代碼修正一下,減去這sq個數字,發現還是多着許多。再仔細看一下不難發現,對於小於sq的因數,每個因數我們都多計算了sq個。綜合前面等於sq的情況,也就是多計算了sq個sq(sq*sq)。這樣說可能比較抽象,舉個例子說一下:

假設x=16,於是,我們求1~16的因數個數的和。

我們是把每個數字的因數都分爲了2部分(小於等於sq和大於sq的兩部分)(sq = 4)

對於數字1,有1個因數(1),我們簡單乘以2,多計算了1次1;

對於數字2,有2因數(1,2),我們簡單乘以2,多計算了1次1,1次2;

對於數字3,有2因數(1,3),我們簡單乘以2,多計算了1次1,1次3;

對於數字4,有2因數(1,2,4),我們簡單乘以2,多計算了1次1,1次2,1次4;

對於數字5,有2因數(1,5),我們簡單乘以2,正好;

對於數字6,有2因數(1,2,3,6),我們簡單乘以2,多計算了1次2,1次3;

對於數字7,有2因數(1,7),我們簡單乘以2,正好;

對於數字8,有2因數(1,2,4,8),我們簡單乘以2,多計算了1次2,1次4;

對於數字9,有2因數(1,3,9),我們簡單乘以2,多計算了1次3;

對於數字10,有2因數(1,2,5,10),我們簡單乘以2,正好;

對於數字11,有2因數(1,11),我們簡單乘以2,正好;

對於數字12,有2因數(1,2,3,4,6,12),我們簡單乘以2,1次3,1次4;

對於數字13,有2因數(1,13),我們簡單乘以2,正好;

對於數字14,有2因數(1,2,7,14),我們簡單乘以2,正好;

對於數字15,有2因數(1,3,5,15),我們簡單乘以2,正好;

對於數字16,有2因數(1,2,4,8,16),我們簡單乘以2,多計算了1次4。

加起來正好是1~sq這sq個因數,每一個都多計算了sq次。所以我們一共多計算了sq*sq次

所以該方法的正確結果應爲2*\sum_{i=1}^{sq}x/i - sq*sq,其中sq爲x的算數平方根。

【代碼】

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<memory.h>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<array>
#include<deque>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define mem(array)  memset((array),0,sizeof((array)))
#define Qsort(array,len,cmp) qsort(array,len,sizeof(array[0]),cmp)
#define inf 0x7fffffff
#define MAXN 10+10000
using namespace std;
int main()
{
    int q;
    int x;
    long long ans;
    while(cin>>q){
        for(int t = 0; t < q; ++t){
            ans = 0;
            scanf("%d",&x);
            int sq = sqrt(x);
            for(int i = 1; i <= sq; ++i){
                ans += x/i;
            }
            cout << 2*ans -sq*sq << endl;
        }
    }
    return 0;
}

 

題目來源於 牛客網

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章