51nod-1225 余数之和(分区间处理)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haut_ykc/article/details/83004760

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

题解:

n有1e12这么大,肯定不能暴力。

我们考虑将区间分成[1,sqrt(n)]和[sqrt(n),n]这两个区间。

对于第一个区间,我们直接累加答案即可。

对于第二个区间我们发现,由于除数很大,其n/i在很大范围内是一样。

并且在n/i相同的这一区间内其贡献满足等差数列,到这里问题就解决了。

#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long 
#define mod 1000000007
ll n,ans,last;
ll inv=500000004;//2的逆元
int main(void)
{
	scanf("%lld",&n);
	ll m=(ll)sqrt(n+0.5);
	for(ll i=1;i<=m;i++)
		ans=(ans+n%i)%mod;
	for(int i=1;i<=m;i++)
	{
		ll num=((n/i)%mod-n/(i+1)%mod+mod)%mod;
		ans=(ans+n%i*num%mod+(num*(num-1)%mod)%mod*inv%mod*i%mod)%mod;
	}
	if(n/m==m) ans=(ans-(n%m)+mod)%mod;
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/haut_ykc/article/details/83004760