1. 程式人生 > >51nod-1225 餘數之和(分割槽間處理)

51nod-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;
}