bzoj P1968

weixin_30588675發表於2020-04-05

這題是十分經典的數學題,在其他各大oj也都有類似(相同)的題目

但是,我們還是從頭開始說

首先,這道題肯定不會是遞推,因為給出的f[1~6]就已經沒有遞推性了。。

所以,應該是一道模擬題(?)

演算法一:從1迴圈到n,每次列舉1~i的所有數,判斷是否為因數,ans++。。。

複雜度比O(n^2)小一些。。

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
int n,ans;
int main(){
  scanf("%d”,&n);
  
  for(int i=1;i<=n;i++)

    for(int j=1;j<=i;j++)

      if(i%j==0) ans++;

  printf("%d",ans);
  return 0;
}

 

 

當然,會超時。。。

演算法二:利用小學數學知識(以及初中的根號),每次從1迴圈到n,列舉1~sqrt(n)(n的根號),

判斷i是否為因數,如果是,則必然有兩個因陣列成i,於是ans+=2。。。(這裡注意特判一下sqrt(n)的情況,這樣的情況ans只加一)

複雜度O(n*sqrt(n)),n<=10^6,最壞複雜度為10^9,會超時。。

程式碼如下

#include<bits/stdc++.h>
using namespace std;
long long n,ans;
int solve(int x){
int cnt=0;
for(int i=1;i<=sqrt(x);i++)
if(x%i==0){
cnt+=2;
if(i==sqrt(x)) cnt--;
}
return cnt;
}
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) ans+=solve(i);
printf("%lld",ans);
return 0;
}

演算法三:用篩法,但是不是正常的篩法:

因數的範圍是在1~n之間的,所以可以倒著考慮,一個數有幾個在1~n範圍內的倍數呢?

因此可以列舉每個1~n的因數,求出他有幾個倍數,然後ans加上倍數個數就行了(連根號都不用特判)。。

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
int n,ans;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) ans+=n/i;
printf("%d",ans);
return 0;
}

 

轉載於:https://www.cnblogs.com/heqingyu/p/7683494.html