Evanyou Blog 彩带

P1403 [AHOI2005]约数研究

题目描述

科学家们在Samuel星球上的探险得到了丰富的能源储备,这使得空间站中大型计算机“Samuel II”的长时间运算成为了可能。由于在去年一年的辛苦工作取得了不错的成绩,小联被允许用“Samuel II”进行数学研究。

小联最近在研究和约数有关的问题,他统计每个正数N的约数的个数,并以f(N)来表示。例如12的约数有1、2、3、4、6、12。因此f(12)=6。下表给出了一些f(N)的取值:

f(n)表示n的约数个数,现在给出n,要求求出f(1)到f(n)的总和。

输入输出格式

输入格式:

输入一行,一个整数n

输出格式:

输出一个整数,表示总和

输入输出样例

输入样例#1: 
3
输出样例#1: 
5

说明

【数据范围】

20%N<=5000

100%N<=1000000

 

Solution:

本题纯考数学,因为需要求1到n的数所含的各自的约数和,我们可以转换为:1~n中是1的倍数的数有n/1个,是2的倍数的有n/2个,是3的倍数的数有n/3个,…直到n/n,于是直接O(n)扫一遍每次ans+=n/i就ok了。

当然上述的方法可以完美解决本题,但有一种适用于更大数据的巧妙优化方法,思路和上面是一样的,但是我们考虑到当i枚举到比较大时,会出现重复的n/i,举个例子:

当n为100时,n/i(1≤i≤100)分别为:
100 50 33 25 20 16 14 12 11 10 9 8 7 7 6 6 5 5 5 5 4 4 4 4 4 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

容易发现出现了许多重复的数,而我们完全没必要重复去算而是直接一次性累加完。

方法是设x=n/i,y=n/x,x表示的是n内i的倍数的个数,y表示n内因子个数为x的最大因子(即i最多枚举到y,每次n/i的值都为x),则显然因子个数为x的i值共y-i+1个,于是ans+=x*(y-i+1),然后i直接变为y+1;

这样去优化的话:复杂度从O(n)变为了O(2*sqrt(n)),在n特别大时,优化效果极其鲜明。

代码:

 

#include<bits/stdc++.h>
#define il inline
#define ll long long
using namespace std;
const int N=1000005;
int n,k;
ll ans;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i=k+1){
        k=n/(n/i);
        ans+=n/i*(k-i+1);
    }
    cout<<ans;
    return 0;
}

 

 

 

 

posted @ 2018-03-15 13:26  five20  阅读(664)  评论(0编辑  收藏  举报
Live2D