CF-edu#5 E - Sum of Remainders -数学-枚举

http://codeforces.com/contest/616/problem/E

给n,m,求Calculate the value of the sum: n mod 1 + n mod 2 + n mod 3 + ... + n mod m

答案对1e9+7取模


一开始不知道怎么做,听了菊苣解说才会了。。。。


把 n%k看成 n-k*(n/k)      n/k是指向下取整

那么sum=  n*m  -    【 1*n/1+ 2*n/2  + ...+ k*n/k +....m*n/m 】;


那么对于后面的部分,当k较小时,直接做,当k较大时,我们可以知道  会有 很多个数 的n/k值是同一个,我们枚举这个n/k值即可

  

// sum: k* [n/k],我们枚举n/k的值,我们称为A值
//从n/end,到n/sqt
//那么对于某个A值,n/A得到对应的起始数x,n/(A+1)得到对应的结束数y
//然后x到y都对应同一个A值,所以直接求x->y的和 乘上A即可


<span style="font-size:12px;">#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std; 
const __int64 mod=1000000007;
__int64 min(__int64 a,__int64 b)
{return a<b?a:b;}

__int64 get (__int64 x)
{
	x%=mod;
	return (x+1)*x/2%mod;
} 

__int64 deal_res(__int64 n,__int64 m)
{
	__int64 end=min(n,m); 
		__int64 ret=0,i;
		int sqt=sqrt(double(n));
		for (i=1;i<=sqt&&i<=end;i++)		
		{
			ret+=n/i*i; ret%=mod;
		} 
		// sum: k* [n/k],我们枚举n/k的值,我们成为A值
		//从n/end,到n/sqt
		//那么对于某个A值,n/A得到对应的起始数x,n/(A+1)得到对应的结束数y
		//然后x到y都对应同一个A值,所以直接求x->y的和 乘上A即可
		sqt++;
		for (i=n/sqt;i>=n/end;i--)		
		{
			__int64 t1=n/i,t2=n/(i+1);
			ret=(ret+  (get(min(end,t1))-get(t2))*i%mod  )%mod;
		}
		return ret%mod;  

}
int main()
{

	__int64 n,m;
	scanf("%I64d%I64d",&n,&m);
	__int64 ans=m%mod*(n%mod)%mod;

	__int64 res=deal_res(n,m);
	ans-=res; 
	while (ans<0)
		ans+=mod;  
	printf("%I64d\n",ans%mod);
	return 0;
	
}</span>


// sum: k* [n/k],我们枚举n/k的值,我们称为A值
//从n/end,到n/sqt
//那么对于某个A值,n/A得到对应的起始数x,n/(A+1)得到对应的结束数y
//然后x到y都对应同一个A值,所以直接求x->y的和 乘上A即可

你可能感兴趣的:(CF-edu#5 E - Sum of Remainders -数学-枚举)