51Nod 1225 余数之和 —— 分区枚举

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1225

 

基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 收藏
 关注
F(n) = (n % 1) + (n % 2) + (n % 3) + ...... (n % n)。其中%表示Mod,也就是余数。 
例如F(6) = 6 % 1 + 6 % 2 + 6 % 3 + 6 % 4 + 6 % 5 + 6 % 6 = 0 + 0 + 0 + 2 + 1 + 0 = 3。
给出n,计算F(n), 由于结果很大,输出Mod 1000000007的结果即可。
 
Input
输入1个数N(2 <= N <= 10^12)。
Output
输出F(n) Mod 1000000007的结果。
Input示例
6
Output示例
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 }
View Code

 

posted on 2018-04-08 21:51  h_z_cong  阅读(256)  评论(0编辑  收藏  举报

导航