题意:要求对于1~n,每个数的约数(不包括1和其本身)的和。
题解:由于题目数据有2*10^9之大,因而不能直接暴力。需要考虑积性函数的特性,由于必定有重复的约数出现,因而可以对重复约数所在的区间进行合并。由于对于较小的约数,其对应的较大的约数重复区间较小,所以可以先将较小的约数进行合并操作,然后对其对应的较大的约数的区间进行求和。以n=10为例,对于约数2而言,1~10中有2的约数的有10/2-1个(要减去2本身),而对于2在1~10内相对应的约数4和5,则可以直接进行求和操作,求和区间为[sqrt(n)+1,n/i] 。所以我们可以在sqrt(n)的范围内求出所有约数。具体代码如下:
#include<cstdio> #include<cmath> using namespace std; typedef long long LL; int main() { LL n; LL ans,m; int T,cas=1; scanf("%d",&T); while(T--) { LL q,p; scanf("%lld",&n); ans=0; m=(LL)sqrt(n); for(LL i=2;i<=m;i++) { q=n/i; ans=ans+(q-1)*i; p=m+1; if(p>q) continue; ans=ans+(q-p+1)*(q+p)/2; } printf("Case %d: %lld\n",cas++,ans); } return 0; }
对于积性函数的前缀和的讨论可以参见:
http://blog.csdn.net/skywalkert/article/details/50500009
浙公网安备 33010602011771号