ZOJ3175【公式化函数的思想】
题意:
给出f(n,m)(m<n)的定义:大于m并且小于n的能整除m的数的个数。
F(n)为m从1至n的f(n,m)的和。
给出n,求F(n)。
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; }