1. 程式人生 > >Harmonic Number (II)(模擬找規律)

Harmonic Number (II)(模擬找規律)

題目來源https://cn.vjudge.net/problem/LightOJ-1245
【題意】
求前n項和,每一項是n/i;
【思路】
分解單個數,可以找到規律,舉例說明。
當n為10時:
i ___1 2 3 4 5 6 7 8 9 10
n/i 10 5 3 2 2 1 1 1 1 1
當n為12時:
i ___1 2 3 4 5 6 7 8 9 10
n/i 12 6 4 3 2 2 1 1 1 1
此時就可以發現n/i後面的幾個數是連在一起的,3,2,1而這些數完全可以按乘法去計算,沒必要逐個相加,再看,第一個數10,i是從3開始進入迴圈的,第二個數也是從三,而3剛好是sqrt(n)(有時候需要大膽去猜),然後,就是計數,會發現,比如n==10時,有6個1,2個2,10/1-10/2==6,10/2-10/3==2,這個時候,看,答案就出來了。而前面的數,就是2^31,開方之後也會變得很小,for迴圈列舉就可以了。
注意一點哦,關鍵是我們列舉到哪呢,若是列舉到sqrt(n),要考慮會不會有重複,什麼時候才會有重複呢?10/3=3,12/3=4,15/3=5;而他們的開方之後的結果都是3,但是如果模擬的話,會發先10的3算多了一次,也就是說,如果n/sqrt(n)==sqrt(n),那就減去sqrt(n)。
【程式碼】

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int
INF=1e9; typedef unsigned long long ll; typedef long long LL; int main() { int T,cases=1; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); int p=sqrt(n); LL sum=0; for(int i=1;i<=p;i++) sum+=((n/i)-(n/(i+1)))*i; // printf("%lld\n",sum);
for(int i=1;i<=p;i++) sum+=n/i; if(p==n/p) sum-=p*1; printf("Case %d: %lld\n",cases++,sum); } }