bzoj P1968
这题是十分经典的数学题,在其他各大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;
}