题目链接:【codeforces 616E】
输入n,m(1<=n,m<=10^13),求n%1+n%2+n%3+……+n%m,数据结果较大,对10^9+7取余
n%i ==> n-[n/i]*i
原式化为n*m - ∑i=1m[n/i]∗i
思路1:l=n/(i+1)+1, r=n/i ==> n/x(l<=x<=r)的值必定等于i
举个例子n=20,m=20,现将n开根号了
i=1 ==> l=11, r=20
i=2 ==> l=7, r=10
i=3 ==>. l=r=6
i=4 ==> l=r=5
那么还应该求n%1*1,n%2*2,n%3*3,n%4*4
所以代码中的las就是标记还剩下几个没有取余
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
#define ll __int64
const ll mod=1e9+7;
int main()
{
ll n, m;
scanf("%I64d%I64d", &n, &m);
ll ans = (n%mod)*(m%mod)%mod, tmp=0, las=m+1;
m = min(m, n);
for(ll i=1; i<=(ll)sqrt(n*1.0); i++)
{
ll l=n/(i+1)+1, r=n/i;
r = min(r, m);
if(l>r) continue;
las = min(las, l);
ll s1=l+r, s2=r-l+1;
if(s1%2==0) s1/=2;
else s2/=2;
s1%=mod, s2%=mod;
s1 = (s1*s2)%mod;
s1 = (s1*i)%mod;
tmp = (tmp + s1)%mod;
}
ans = (ans- tmp +mod )% mod;
for(int i=1; i<las; i++)
{
tmp = n/i%mod*i%mod;
ans = (ans- tmp +mod)% mod;
}
printf("%I64d\n", ans);
return 0;
}
思路2:l=i, r=n/(n/i) ==> n/x(l<=x<=r)的值必定是i
跟上面的思路是极像的,只不过这种方法并没有将n开根号,看懂了上面的,这个应该也懂的差不多了
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
#define ll __int64
ll mod=1e9+7;
int main()
{
ll n, m;
scanf("%I64d%I64d", &n, &m);
ll ans = n%mod*(m%mod)%mod;
ll sum=0, j, mm;
for(ll i=1; i<=min(n, m); i++)
{
j = min(n/(n/i), m);
ll s1 = i+j, s2 = j-i+1;
if(s1%2==0) s1 = (s1/2)%mod, s2%=mod;
else s1%=mod, s2 = (s2/2)%mod;
mm = s1*s2%mod*(n/i%mod)%mod;
sum = (sum+mm)%mod;
i = j;
}
ans = (ans-sum+mod)%mod;
printf("%I64d\n", ans);
return 0;
}