题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1225
输入1个数N(2 <= N <= 10^12)。
输出F(n) Mod 1000000007的结果。
6
3
题解:
这题(LightOJ1245)的加强版,本来是求sigma(n/i) 1<=i<=n,而此题求的是:sigma(n%i) 1<=i<=n。
分两个区间枚举:
第一个区间 [1,sqrt(n)]:设i为除数,从1到sqrt(n)枚举i, 直接 ans += n%i;
第二个区间 [sqrt(n), n]:设i为商,从1到sqrt(n)枚举i,由于用后面区间的数去除n所得到的商,在很大一片区域是相同的,在这片区域,他们的余数成等差数列,且公差即为商,所以就可根据等差数列的求和公式,求出这段区域的余数和了。
需要特判在sqrt(n)处是否重复计算了。
代码如下:


1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int MOD = 1e9+7; 17 const int MAXM = 1e5+10; 18 const int MAXN = 1e6+10; 19 20 //inv(2,MOD-2) = 500000004 21 int main() 22 { 23 LL n; 24 while(scanf("%lld", &n)!=EOF) 25 { 26 LL m = (LL)sqrt(n); 27 LL ans = 0; 28 for(LL i = 1; i<=m; i++) 29 ans = (ans+n%i)%MOD; 30 for(LL i = 1; i<=m; i++) 31 { 32 LL cnt = ((n/i)%MOD-(n/(i+1))%MOD+MOD)%MOD; //求个数也要求模 33 LL a1 = n%i; 34 LL s = (a1*cnt%MOD + ((cnt*(cnt-1)%MOD)*500000004LL%MOD)*i%MOD)%MOD; 35 ans = (ans+s)%MOD; 36 } 37 38 if(n/m==m) ans = (ans-(n%m)+MOD)%MOD; 39 printf("%lld\n",ans); 40 } 41 }