ZOJ3175【公式化函数的思想】

题意:

 给出f(n,m)(m<n)的定义:大于m并且小于n的能整除m的数的个数。
F(n)为m从1至n的f(n,m)的和。
给出n,求F(n)。

思路:

就是计算n/1 +  n/2 + n/3 + ... +n/n - n的值;

然后算那个分式的和的话不能O(N),发现n不变,就随手画了个n/x的函数,如下图是y=10/x的函数图;


我们发现这个函数图像是和y=x对称的,这个是其次,然后顺着这个感觉,可以发现,我们从1枚举到sqrt(n),在1的时候10/1=10,在2的时候10/2=5,我们可以很显然的得知,在对应y的区间 (5,10] 对于10/x来说的答案都是1,然后在3的时候10/3=3,我们又能发现y的范围在区间(3,5]上的答案都是2。对于n=10这个情况,在枚举 [1 , sqrt(n)] 每次加上n/i,并且加上对应之前 ( n/(i-1) , n/i ] 的答案都是i-1 ,这样我们对于10这样正好处理了1到n所有的数。

但是如果是20的话,sqrt(20)=4,这样简单加到了4,我们发现我们对于区间的处理都是前闭后开,所以在i=4时,没有处理n/i=5的情况,所以最后还要把 (sqrt(n) , n/sqrt(n)] 这个区间里的答案都加上;然而爆long long wa了一发;

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL n;
        scanf("%lld",&n);
        LL sum=0;
        LL q=sqrt(n);
        sum=n;
        for(LL i=2;i<=q;i++)
        {
            sum=sum+n/i;
            sum=sum+(i-1)*(n/(i-1)-n/i);
        }
        if(n/q>q)
        {
            sum=sum+q*(n/q-n/(q+1));
        }
        printf("%lld\n",sum-n);
    }
    return 0;
}


posted @ 2017-01-18 20:04  see_you_later  阅读(156)  评论(0编辑  收藏  举报